X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/bac41a7b9a0a9254fa30f8bb6e6038ab71a483e2..67c7378dcb8de24c86b7fedff90b4b496f2e474c:/Keychain/StorageManager.cpp diff --git a/Keychain/StorageManager.cpp b/Keychain/StorageManager.cpp index 78194a43..ed3a7875 100644 --- a/Keychain/StorageManager.cpp +++ b/Keychain/StorageManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). @@ -21,9 +21,6 @@ Contains: Working with multiple keychains - Copyright: 2000 by Apple Computer, Inc., all rights reserved. - - To Do: */ #include "StorageManager.h" @@ -39,6 +36,7 @@ #include #include #include +#include #include "KCCursor.h" #include "Globals.h" @@ -50,53 +48,73 @@ using namespace KeychainCore; StorageManager::StorageManager() : mSavedList(), mKeychains(), - mMultiDLDb(mSavedList.list(), true) // Passinng true enables use of Secure Storage + mSearchList() { + _doReload(); } // Create KC if it doesn't exist Keychain StorageManager::keychain(const DLDbIdentifier &dLDbIdentifier) { - //StLock _(mKeychainsLock); + StLock _(mLock); + return _keychain(dLDbIdentifier); +} + +Keychain +StorageManager::_keychain(const DLDbIdentifier &dLDbIdentifier) +{ KeychainMap::iterator it = mKeychains.find(dLDbIdentifier); if (it != mKeychains.end()) return it->second; // The keychain is not in our cache. Create it. - Keychain keychain(mMultiDLDb->database(dLDbIdentifier)); + Module module(dLDbIdentifier.ssuid().guid()); + DL dl; + if (dLDbIdentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP) + dl = SSCSPDL(module); + else + dl = DL(module); + + dl->subserviceId(dLDbIdentifier.ssuid().subserviceId()); + dl->version(dLDbIdentifier.ssuid().version()); + Db db(dl, dLDbIdentifier.dbName()); + Keychain keychain(db); // Add the keychain to the cache. mKeychains.insert(KeychainMap::value_type(dLDbIdentifier, keychain)); return keychain; } -// Create KC if it doesn't exist +// Create KC if it doesn't exist, add it to the search list if it exists and is not already on it. Keychain StorageManager::makeKeychain(const DLDbIdentifier &dLDbIdentifier) { Keychain keychain(keychain(dLDbIdentifier)); - const vector &list = mMultiDLDb->list(); - if (find(list.begin(), list.end(), dLDbIdentifier) != list.end()) { - // The dLDbIdentifier for this keychain is already on our search list. - return keychain; + StLock _(mLock); + if (find(mSearchList.begin(), mSearchList.end(), keychain) != mSearchList.end()) + { + // This keychain is already on our search list. + return keychain; + } + + // If the keychain doesn't exist don't bother adding it to the search list yet. + if (!keychain->exists()) + return keychain; + + // The keychain exists and is not in our search list add it to the search + // list and the cache. Then inform mMultiDLDb. + mSavedList.revert(true); + mSavedList.add(dLDbIdentifier); + mSavedList.save(); + + // @@@ Will happen again when kSecKeychainListChangedEvent notification is received. + _doReload(); } - // If the keychain doesn't exist don't bother adding it to the search list yet. - if (!keychain->exists()) - return keychain; - - // The keychain exists and is not in our search list add it to the search - // list and the cache. Then inform mMultiDLDb. - mSavedList.revert(true); - mSavedList.add(dLDbIdentifier); - mSavedList.save(); - - // @@@ Will happen again when kSecKeychainListChangedEvent notification is received. - mMultiDLDb->list(mSavedList.list()); - + // Make sure we are not holding mLock when we post this event. KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); return keychain; @@ -106,70 +124,108 @@ void StorageManager::created(const Keychain &keychain) // Be notified a Keychain just got created. { DLDbIdentifier dLDbIdentifier = keychain->dLDbIdentifier(); - - // If we don't have a default Keychain yet. Make the newly created keychain the default. - DefaultKeychain &defaultKeychain = globals().defaultKeychain; - if (!defaultKeychain.isSet()) - defaultKeychain.dLDbIdentifier(dLDbIdentifier); - // Add the keychain to the search list and the cache. Then inform mMultiDLDb. - mSavedList.revert(true); - mSavedList.add(dLDbIdentifier); - mSavedList.save(); + { + StLock _(mLock); - // @@@ Will happen again when kSecKeychainListChangedEvent notification is received. - mMultiDLDb->list(mSavedList.list()); + // If we don't have a default Keychain yet. Make the newly created keychain the default. + DefaultKeychain &defaultKeychain = globals().defaultKeychain; + if (!defaultKeychain.isSet()) + defaultKeychain.dLDbIdentifier(dLDbIdentifier); + + // Add the keychain to the search list and the cache. Then inform mMultiDLDb. + mSavedList.revert(true); + mSavedList.add(dLDbIdentifier); + mSavedList.save(); + + // @@@ Will happen again when kSecKeychainListChangedEvent notification is received. + _doReload(); + } + // Make sure we are not holding mLock when we post this event. KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); } - KCCursor StorageManager::createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList) { - return KCCursor(DbCursor(mMultiDLDb), itemClass, attrList); + StLock _(mLock); + return KCCursor(mSearchList, itemClass, attrList); } KCCursor StorageManager::createCursor(const SecKeychainAttributeList *attrList) { - return KCCursor(DbCursor(mMultiDLDb), attrList); + StLock _(mLock); + return KCCursor(mSearchList, attrList); } void StorageManager::lockAll() { - for (KeychainMap::iterator ix = mKeychains.begin(); ix != mKeychains.end(); ix++) + // Make a snapshot of all known keychains while holding mLock. + KeychainList keychainList; { - Keychain keychain(ix->second); + StLock _(mLock); + for (KeychainMap::iterator ix = mKeychains.begin(); ix != mKeychains.end(); ix++) + keychainList.push_back(ix->second); + } + + // Lock each active keychain after having released mLock since locking keychains + // will send notifications. + for (KeychainList::iterator ix = keychainList.begin(); ix != keychainList.end(); ++ix) + { + Keychain keychain = *ix; if (keychain->isActive()) keychain->lock(); } } +void +StorageManager::_doReload() +{ + KeychainList newList; + newList.reserve(mSavedList.size()); + for (CssmClient::DLDbList::iterator ix = mSavedList.begin(); ix != mSavedList.end(); ++ix) + { + Keychain keychain(_keychain(*ix)); + newList.push_back(keychain); + } + mSearchList.swap(newList); +} + void StorageManager::reload(bool force) +{ + StLock _(mLock); + _reload(force); +} + +void +StorageManager::_reload(bool force) { // Reinitialize list from CFPrefs if changed. When force is true force a prefs revert now. if (mSavedList.revert(force)) - mMultiDLDb->list(mSavedList.list()); + _doReload(); } size_t StorageManager::size() { - reload(); - return mMultiDLDb->list().size(); + StLock _(mLock); + _reload(); + return mSearchList.size(); } Keychain StorageManager::at(unsigned int ix) { - reload(); - if (ix >= mMultiDLDb->list().size()) + StLock _(mLock); + _reload(); + if (ix >= mSearchList.size()) MacOSError::throwMe(errSecInvalidKeychain); - return keychain(mMultiDLDb->list().at(ix)); + return mSearchList.at(ix); } Keychain @@ -178,76 +234,124 @@ StorageManager::operator[](unsigned int ix) return at(ix); } -void StorageManager::remove(const list& kcsToRemove) +void StorageManager::remove(const KeychainList &kcsToRemove, bool deleteDb) { - //StLock _(mKeychainsLock); - mSavedList.revert(true); - DLDbIdentifier defaultId = globals().defaultKeychain.dLDbIdentifier(); - bool unsetDefault=false; - for (list::const_iterator ix = kcsToRemove.begin();ix!=kcsToRemove.end();ix++) + bool unsetDefault = false; { - // Find the keychain object for the given ref - Keychain keychainToRemove; - try - { - keychainToRemove = KeychainRef::required(*ix); - } - catch (const MacOSError& err) + StLock _(mLock); + mSavedList.revert(true); + DLDbIdentifier defaultId = globals().defaultKeychain.dLDbIdentifier(); + for (KeychainList::const_iterator ix = kcsToRemove.begin(); ix != kcsToRemove.end(); ++ix) { - if (err.osStatus() == errSecInvalidKeychain) - continue; - throw; + // Find the keychain object for the given ref + Keychain keychainToRemove = *ix; + DLDbIdentifier dLDbIdentifier = keychainToRemove->dLDbIdentifier(); + + // Remove it from the saved list + mSavedList.remove(dLDbIdentifier); + if (dLDbIdentifier == defaultId) + unsetDefault=true; + + if (deleteDb) + { + keychainToRemove->database()->deleteDb(); + // Now remove it from the map + KeychainMap::iterator it = mKeychains.find(dLDbIdentifier); + if (it == mKeychains.end()) + continue; + mKeychains.erase(it); + } } - - // Remove it from the saved list - mSavedList.remove(keychainToRemove->dLDbIdentifier()); - if (keychainToRemove->dLDbIdentifier() == defaultId) - unsetDefault=true; - // Now remove it from the map - KeychainMap::iterator it = mKeychains.find(keychainToRemove->dLDbIdentifier()); - if (it==mKeychains.end()) - continue; - mKeychains.erase(it); + mSavedList.save(); + _doReload(); } - mSavedList.save(); - mMultiDLDb->list(mSavedList.list()); + + // Make sure we are not holding mLock when we post this event. KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); + if (unsetDefault) + { + // Make sure we are not holding mLock when we call this since it posts an event. globals().defaultKeychain.unset(); + } +} + +void +StorageManager::getSearchList(KeychainList &keychainList) +{ + // Make a copy of the searchList + StLock _(mLock); + StorageManager::KeychainList searchList(mSearchList); + + // Return the copy of the list. + keychainList.swap(searchList); } -void StorageManager::replace(const list& newKCList) +void +StorageManager::setSearchList(const KeychainList &keychainList) { - // replace keychains list with new list - CssmClient::DLDbList dldbList; - convert(newKCList,dldbList); + // Make a copy of the passed in searchList + StorageManager::KeychainList keychains(keychainList); + + // Set the current searchlist to be what was passed in, the old list will be freed + // upon exit of this stackframe. + StLock _(mLock); + mSearchList.swap(keychains); } -void StorageManager::convert(const list& SecKeychainRefList,CssmClient::DLDbList& dldbList) +void +StorageManager::optionalSearchList(CFTypeRef keychainOrArray, KeychainList &keychainList) { - // Convert a list of SecKeychainRefs to a DLDbList - dldbList.clear(); // If we don't clear list, we should use "add" instead of push_back - for (list::const_iterator ix = SecKeychainRefList.begin();ix!=SecKeychainRefList.end();ix++) + if (!keychainOrArray) + getSearchList(keychainList); + else { - // Find the keychain object for the given ref - Keychain keychain; - try - { - keychain = KeychainRef::required(*ix); - } - catch (const MacOSError& err) - { - if (err.osStatus() == errSecInvalidKeychain) - continue; - throw; - } - - // Add it to the list - dldbList.push_back(keychain->dLDbIdentifier()); + CFTypeID typeID = CFGetTypeID(keychainOrArray); + if (typeID == CFArrayGetTypeID()) + convertToKeychainList(CFArrayRef(keychainOrArray), keychainList); + else if (typeID == gTypes().keychain.typeId) + keychainList.push_back(gTypes().keychain.required(SecKeychainRef(keychainOrArray))); + else + MacOSError::throwMe(paramErr); + } +} + +// static methods. +void +StorageManager::convertToKeychainList(CFArrayRef keychainArray, KeychainList &keychainList) +{ + assert(keychainArray); + CFIndex count = CFArrayGetCount(keychainArray); + KeychainList keychains(count); + CFClass &kcClass = gTypes().keychain; + for (CFIndex ix = 0; ix < count; ++ix) + { + keychains[ix] = kcClass.required(SecKeychainRef(CFArrayGetValueAtIndex(keychainArray, ix))); + } + + keychainList.swap(keychains); +} + +CFArrayRef +StorageManager::convertFromKeychainList(const KeychainList &keychainList) +{ + CFRef keychainArray(CFArrayCreateMutable(NULL, keychainList.size(), &kCFTypeArrayCallBacks)); + + CFClass &kcClass = gTypes().keychain; + for (KeychainList::const_iterator ix = keychainList.begin(); ix != keychainList.end(); ++ix) + { + SecKeychainRef keychainRef = kcClass.handle(**ix); + CFArrayAppendValue(keychainArray, keychainRef); + CFRelease(keychainRef); } + + // Counter the CFRelease that CFRef<> is about to do when keychainArray goes out of scope. + CFRetain(keychainArray); + return keychainArray; } + #pragma mark ÑÑÑÑ Login Functions ÑÑÑÑ void StorageManager::login(ConstStringPtr name, ConstStringPtr password) @@ -262,10 +366,12 @@ void StorageManager::login(UInt32 nameLength, const void *name, UInt32 passwordL { // @@@ set up the login session on behalf of loginwindow // @@@ (this code should migrate into loginwindow) +#if 0 debug("KClogin", "setting up login session"); if (OSStatus ssnErr = SessionCreate(sessionKeepCurrentBootstrap, sessionHasGraphicAccess | sessionHasTTY)) - debug("KClogin", "session setup failed status=%ld", ssnErr); + debug("KClogin", "session setup failed status=%ld", ssnErr); +#endif if (name == NULL || (passwordLength != 0 && password == NULL)) MacOSError::throwMe(paramErr); @@ -287,7 +393,7 @@ void StorageManager::login(UInt32 nameLength, const void *name, UInt32 passwordL // Login Keychain does not lock on sleep nor lock after timeout by default. keychain->setSettings(INT_MAX, false); } - +#if 0 // @@@ Create a authorization credential for the current user. debug("KClogin", "creating login authorization"); const AuthorizationItem envList[] = @@ -304,6 +410,7 @@ void StorageManager::login(UInt32 nameLength, const void *name, UInt32 passwordL if (OSStatus authErr = AuthorizationCreate(NULL, &environment, kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize, NULL)) debug("KClogin", "failed to create login auth, status=%ld", authErr); +#endif } void StorageManager::logout() @@ -352,15 +459,16 @@ Keychain StorageManager::make(const char *pathName) const CSSM_VERSION *version = NULL; uint32 subserviceId = 0; CSSM_SERVICE_TYPE subserviceType = CSSM_SERVICE_DL | CSSM_SERVICE_CSP; - const CssmSubserviceUid ssuid( gGuidAppleCSPDL, version, - subserviceId, subserviceType ); - DLDbIdentifier dLDbIdentifier( ssuid, fullPathName.c_str(), DbLocation ); - return makeKeychain( dLDbIdentifier ); + const CssmSubserviceUid ssuid(gGuidAppleCSPDL, version, + subserviceId, subserviceType); + DLDbIdentifier dLDbIdentifier(ssuid, fullPathName.c_str(), DbLocation); + return makeKeychain(dLDbIdentifier); } KeychainSchema StorageManager::keychainSchemaFor(const CssmClient::Db &db) { + // @@@ Locking KeychainSchema schema(db); pair result = mKeychainSchemaSet.insert(db); if (result.second)