2 * Copyright (c) 2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
29 #include "DynamicDLDBList.h"
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"
39 using namespace KeychainCore
;
44 DynamicDLDBList::DynamicDLDBList()
45 : mMutex(Mutex::recursive
), mSearchListSet(false)
49 DynamicDLDBList::~DynamicDLDBList()
54 DynamicDLDBList::appNotifyCallback(const CSSM_GUID
*guid
, void *context
,
55 uint32 subserviceId
, CSSM_SERVICE_TYPE subserviceType
, CSSM_MODULE_EVENT eventType
)
57 CSSM_RETURN status
= 0;
60 reinterpret_cast<DynamicDLDBList
*>(context
)->callback(Guid::required(guid
),
61 subserviceId
, subserviceType
, eventType
);
63 catch (const CommonError
&error
)
65 status
= error
.osStatus();
74 /* Assume mLock is locked already. Add all databases for this module. */
76 DynamicDLDBList::_add(const Guid
&guid
, uint32 subserviceID
, CSSM_SERVICE_TYPE subserviceType
)
78 return _add(dlDbIdentifier(guid
, subserviceID
, subserviceType
));
81 /* Assume mLock is locked already. Add a single database to the searchlist. */
83 DynamicDLDBList::_add(const DLDbIdentifier
&dlDbIdentifier
)
85 StLock
<Mutex
>_(mMutex
);
87 if (find(mSearchList
.begin(), mSearchList
.end(), dlDbIdentifier
) == mSearchList
.end())
89 mSearchList
.push_back(dlDbIdentifier
);
96 /* Assume mLock is locked already. Remove all databases for this module. */
98 DynamicDLDBList::_remove(const Guid
&guid
, uint32 subserviceID
, CSSM_SERVICE_TYPE subserviceType
)
100 return _remove(dlDbIdentifier(guid
, subserviceID
, subserviceType
));
103 /* Assume mLock is locked already. Remove a single database from the
106 DynamicDLDBList::_remove(const DLDbIdentifier
&dlDbIdentifier
)
108 StLock
<Mutex
>_(mMutex
);
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())
114 mSearchList
.erase(it
);
116 // Remove from the storageManager cache if it was there.
117 globals().storageManager
.didRemoveKeychain(dlDbIdentifier
);
125 DynamicDLDBList::_load()
127 StLock
<Mutex
>_(mMutex
);
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
);
135 for (MDSClient::Table
<MDSClient::Common
>::iterator commonIt
=
136 common
.find(MDSClient::Attribute("DynamicFlag") != false);
137 commonIt
!= common
.end(); ++commonIt
)
139 CSSM_SERVICE_MASK serviceMask
= (*commonIt
)->serviceMask();
140 if (serviceMask
& CSSM_SERVICE_DL
)
142 string moduleID
= (*commonIt
)->moduleID();
143 secinfo("dynamic", "Loading dynamic %sDL module: %s",
144 (serviceMask
& CSSM_SERVICE_CSP
) ? "CSP/" : "", moduleID
.c_str());
146 /* Register module for callbacks and load it. */
147 Guid
moduleGuid(moduleID
);
148 CssmClient::Module
module(moduleGuid
);
149 module->appNotifyCallback(appNotifyCallback
, this);
151 mModules
.push_back(module);
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
)
159 uint32 subserviceID
= (*dlIt
)->subserviceID();
160 bool hasCSP
= csp
.find(MDSClient::Attribute("ModuleID") == moduleID
161 && MDSClient::Attribute("SSID") == subserviceID
) != csp
.end();
163 secinfo("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
);
174 const vector
<DLDbIdentifier
> &
175 DynamicDLDBList::searchList()
177 StLock
<Mutex
>_(mMutex
);
180 // Load all dynamic DL's so we start receiving notifications.
183 mSearchListSet
= true;
190 DynamicDLDBList::callback(const Guid
&guid
, uint32 subserviceID
,
191 CSSM_SERVICE_TYPE subserviceType
, CSSM_MODULE_EVENT eventType
)
193 secinfo("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
);
196 StLock
<Mutex
>_(mMutex
);
198 bool list_changed
= false;
200 if (subserviceType
& CSSM_SERVICE_DL
)
202 if (eventType
== CSSM_NOTIFY_INSERT
)
204 /* A DL or CSP/DL was inserted. */
205 secinfo("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
);
209 else if (eventType
== CSSM_NOTIFY_REMOVE
)
211 /* A DL or CSP/DL was removed. */
212 secinfo("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
);
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
);
227 DLDbIdentifier
DynamicDLDBList::dlDbIdentifier(const Guid
&guid
,
228 uint32 subserviceID
, CSSM_SERVICE_TYPE subserviceType
)
230 CSSM_VERSION theVersion
={};
231 CssmSubserviceUid
ssuid(guid
, &theVersion
, subserviceID
, subserviceType
);
232 CssmNetAddress
*dbLocation
=NULL
;
234 return DLDbIdentifier(ssuid
, NULL
, dbLocation
);