X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_keychain/lib/DynamicDLDBList.cpp?ds=sidebyside diff --git a/Security/libsecurity_keychain/lib/DynamicDLDBList.cpp b/Security/libsecurity_keychain/lib/DynamicDLDBList.cpp new file mode 100644 index 00000000..0539e474 --- /dev/null +++ b/Security/libsecurity_keychain/lib/DynamicDLDBList.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2004,2011,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +/* + DynamicDLDBList.cpp +*/ + +#include "DynamicDLDBList.h" + +#include "Globals.h" + +#include +#include // For Required() +#include +#include +#include "KCEventNotifier.h" + +using namespace KeychainCore; + +// +// DynamicDLDBList +// +DynamicDLDBList::DynamicDLDBList() + : mMutex(Mutex::recursive), mSearchListSet(false) +{ +} + +DynamicDLDBList::~DynamicDLDBList() +{ +} + +CSSM_RETURN +DynamicDLDBList::appNotifyCallback(const CSSM_GUID *guid, void *context, + uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType, CSSM_MODULE_EVENT eventType) +{ + CSSM_RETURN status = 0; + try + { + reinterpret_cast(context)->callback(Guid::required(guid), + subserviceId, subserviceType, eventType); + } + catch (const CommonError &error) + { + status = error.osStatus(); + } + catch (...) + { + } + + return status; +} + +/* Assume mLock is locked already. Add all databases for this module. */ +bool +DynamicDLDBList::_add(const Guid &guid, uint32 subserviceID, CSSM_SERVICE_TYPE subserviceType) +{ + return _add(dlDbIdentifier(guid, subserviceID, subserviceType)); +} + +/* Assume mLock is locked already. Add a single database to the searchlist. */ +bool +DynamicDLDBList::_add(const DLDbIdentifier &dlDbIdentifier) +{ + StLock_(mMutex); + + if (find(mSearchList.begin(), mSearchList.end(), dlDbIdentifier) == mSearchList.end()) + { + mSearchList.push_back(dlDbIdentifier); + return true; + } + + return false; +} + +/* Assume mLock is locked already. Remove all databases for this module. */ +bool +DynamicDLDBList::_remove(const Guid &guid, uint32 subserviceID, CSSM_SERVICE_TYPE subserviceType) +{ + return _remove(dlDbIdentifier(guid, subserviceID, subserviceType)); +} + +/* Assume mLock is locked already. Remove a single database from the + searchlist. */ +bool +DynamicDLDBList::_remove(const DLDbIdentifier &dlDbIdentifier) +{ + StLock_(mMutex); + + // search for subserviceUid but ignore the dbName, which is dynamic + for (SearchList::iterator it = mSearchList.begin(); it != mSearchList.end(); it++) + if (it->ssuid() == dlDbIdentifier.ssuid()) + { + mSearchList.erase(it); + + // Remove from the storageManager cache if it was there. + globals().storageManager.didRemoveKeychain(dlDbIdentifier); + return true; + } + // not found + return false; +} + +bool +DynamicDLDBList::_load() +{ + StLock_(mMutex); + + bool list_changed = false; + MDSClient::Directory &mds = MDSClient::mds(); + MDSClient::Table common(mds); + MDSClient::Table dl(mds); + MDSClient::Table csp(mds); + + for (MDSClient::Table::iterator commonIt = + common.find(MDSClient::Attribute("DynamicFlag") != false); + commonIt != common.end(); ++commonIt) + { + CSSM_SERVICE_MASK serviceMask = (*commonIt)->serviceMask(); + if (serviceMask & CSSM_SERVICE_DL) + { + string moduleID = (*commonIt)->moduleID(); + secdebug("dynamic", "Loading dynamic %sDL module: %s", + (serviceMask & CSSM_SERVICE_CSP) ? "CSP/" : "", moduleID.c_str()); + + /* Register module for callbacks and load it. */ + Guid moduleGuid(moduleID); + CssmClient::Module module(moduleGuid); + module->appNotifyCallback(appNotifyCallback, this); + module->load(); + mModules.push_back(module); + + /* Now that we have registered for notifications, Find all already + registered dl subsevices for this module. */ + for (MDSClient::Table::iterator dlIt = + dl.find(MDSClient::Attribute("ModuleID") == moduleID); + dlIt!= dl.end(); ++dlIt) + { + uint32 subserviceID = (*dlIt)->subserviceID(); + bool hasCSP = csp.find(MDSClient::Attribute("ModuleID") == moduleID + && MDSClient::Attribute("SSID") == subserviceID) != csp.end(); + + secdebug("dynamic", "Adding databases from %sDL SSID %lu module: %s", + hasCSP ? "CSP/" : "", (unsigned long)subserviceID, moduleID.c_str()); + list_changed |= _add(moduleGuid, subserviceID, + hasCSP ? CSSM_SERVICE_CSP | CSSM_SERVICE_DL : CSSM_SERVICE_DL); + } + } + } + + return list_changed; +} + +const vector & +DynamicDLDBList::searchList() +{ + StLock_(mMutex); + if (!mSearchListSet) + { + // Load all dynamic DL's so we start receiving notifications. + _load(); + + mSearchListSet = true; + } + + return mSearchList; +} + +void +DynamicDLDBList::callback(const Guid &guid, uint32 subserviceID, + CSSM_SERVICE_TYPE subserviceType, CSSM_MODULE_EVENT eventType) +{ + secdebug("event", "Received callback from guid: %s ssid: %lu type: %lu event: %lu", + guid.toString().c_str(), (unsigned long)subserviceID, (unsigned long)subserviceType, (unsigned long)eventType); + + StLock_(mMutex); + + bool list_changed = false; + + if (subserviceType & CSSM_SERVICE_DL) + { + if (eventType == CSSM_NOTIFY_INSERT) + { + /* A DL or CSP/DL was inserted. */ + secdebug("dynamic", "%sDL module: %s SSID: %lu inserted", + (subserviceType & CSSM_SERVICE_CSP) ? "CSP/" : "", guid.toString().c_str(), (unsigned long)subserviceID); + list_changed = _add(guid, subserviceID, subserviceType); + } + else if (eventType == CSSM_NOTIFY_REMOVE) + { + /* A DL or CSP/DL was removed. */ + secdebug("dynamic", "%sDL module: %s SSID: %lu removed", + (subserviceType & CSSM_SERVICE_CSP) ? "CSP/" : "", guid.toString().c_str(), (unsigned long)subserviceID); + list_changed = _remove(guid, subserviceID, subserviceType); + } + } + + if (list_changed) + { + // Make sure we are not holding mLock nor the StorageManager mLock when we post these events. + // @@@ Rather than posting we should simulate a receive since each client will receive this + // cssm level notification. + KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); + } +} + +DLDbIdentifier DynamicDLDBList::dlDbIdentifier(const Guid &guid, + uint32 subserviceID, CSSM_SERVICE_TYPE subserviceType) +{ + CSSM_VERSION theVersion={}; + CssmSubserviceUid ssuid(guid, &theVersion, subserviceID, subserviceType); + CssmNetAddress *dbLocation=NULL; + + return DLDbIdentifier(ssuid, NULL, dbLocation); +}