]> git.saurik.com Git - apple/security.git/blobdiff - Keychain/Keychains.cpp
Security-222.tar.gz
[apple/security.git] / Keychain / Keychains.cpp
diff --git a/Keychain/Keychains.cpp b/Keychain/Keychains.cpp
deleted file mode 100644 (file)
index ae053cf..0000000
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * Copyright (c) 2000-2001 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').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- * 
- * This 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.
- */
-
-
-//
-// Keychains.cpp
-//
-
-#include "Keychains.h"
-#include "KCEventNotifier.h"
-
-#include "Item.h"
-#include "KCCursor.h"
-#include "Globals.h"
-#include "Schema.h"
-#include <Security/keychainacl.h>
-#include <Security/cssmacl.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <Security/cssmdb.h>
-#include <Security/trackingallocator.h>
-#include <Security/SecCFTypes.h>
-
-using namespace KeychainCore;
-using namespace CssmClient;
-
-
-//
-// KeychainSchemaImpl
-//
-KeychainSchemaImpl::KeychainSchemaImpl(const Db &db)
-{
-       DbCursor relations(db);
-       relations->recordType(CSSM_DL_DB_SCHEMA_INFO);
-       DbAttributes relationRecord(db, 1);
-       relationRecord.add(Schema::RelationID);
-       DbUniqueRecord outerUniqueId(db);
-
-       while (relations->next(&relationRecord, NULL, outerUniqueId))
-       {
-               DbUniqueRecord uniqueId(db);
-
-               uint32 relationID = relationRecord.at(0);
-               if (CSSM_DB_RECORDTYPE_SCHEMA_START <= relationID && relationID < CSSM_DB_RECORDTYPE_SCHEMA_END)
-                       continue;
-
-               // Create a cursor on the SCHEMA_ATTRIBUTES table for records with RelationID == relationID
-               DbCursor attributes(db);
-               attributes->recordType(CSSM_DL_DB_SCHEMA_ATTRIBUTES);
-               attributes->add(CSSM_DB_EQUAL, Schema::RelationID, relationID);
-       
-               // Set up a record for retriving the SCHEMA_ATTRIBUTES
-               DbAttributes attributeRecord(db, 2);
-               attributeRecord.add(Schema::AttributeFormat);
-               attributeRecord.add(Schema::AttributeID);
-               attributeRecord.add(Schema::AttributeNameFormat);
-       
-       
-               RelationInfoMap &rim = mDatabaseInfoMap[relationID];
-               while (attributes->next(&attributeRecord, NULL, uniqueId))
-               {
-                       // @@@ this if statement was blocking tags of different naming conventions
-                       //if(CSSM_DB_ATTRIBUTE_FORMAT(attributeRecord.at(2))==CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER)
-                               rim[attributeRecord.at(1)] = attributeRecord.at(0);
-               }
-               
-               // Create a cursor on the CSSM_DL_DB_SCHEMA_INDEXES table for records with RelationID == relationID
-               DbCursor indexes(db);
-               indexes->recordType(CSSM_DL_DB_SCHEMA_INDEXES);
-               indexes->conjunctive(CSSM_DB_AND);
-               indexes->add(CSSM_DB_EQUAL, Schema::RelationID, relationID);
-               indexes->add(CSSM_DB_EQUAL, Schema::IndexType, uint32(CSSM_DB_INDEX_UNIQUE));
-
-               // Set up a record for retriving the SCHEMA_INDEXES
-               DbAttributes indexRecord(db, 1);
-               indexRecord.add(Schema::AttributeID);
-
-               CssmAutoDbRecordAttributeInfo &infos = *new CssmAutoDbRecordAttributeInfo();
-               mPrimaryKeyInfoMap.insert(PrimaryKeyInfoMap::value_type(relationID, &infos));
-               infos.DataRecordType = relationID;
-               while (indexes->next(&indexRecord, NULL, uniqueId))
-               {
-                       CssmDbAttributeInfo &info = infos.add();
-                       info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
-                       info.Label.AttributeID = indexRecord.at(0);
-                       info.AttributeFormat = rim[info.Label.AttributeID]; // @@@ Might insert bogus value if DB is corrupt
-               }
-       }
-}
-
-KeychainSchemaImpl::~KeychainSchemaImpl()
-{
-       for_each_map_delete(mPrimaryKeyInfoMap.begin(), mPrimaryKeyInfoMap.end());
-}
-
-const KeychainSchemaImpl::RelationInfoMap &
-KeychainSchemaImpl::relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const
-{
-       DatabaseInfoMap::const_iterator dit = mDatabaseInfoMap.find(recordType);
-       if (dit == mDatabaseInfoMap.end())
-               MacOSError::throwMe(errSecNoSuchClass);
-       return dit->second;
-}
-
-bool
-KeychainSchemaImpl::hasAttribute(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const
-{
-       const RelationInfoMap &rmap = relationInfoMapFor(recordType);
-       RelationInfoMap::const_iterator rit = rmap.find(attributeId);
-       return rit != rmap.end();
-}
-
-CSSM_DB_ATTRIBUTE_FORMAT 
-KeychainSchemaImpl::attributeFormatFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const
-{
-       const RelationInfoMap &rmap = relationInfoMapFor(recordType);
-       RelationInfoMap::const_iterator rit = rmap.find(attributeId);
-       if (rit == rmap.end())
-               MacOSError::throwMe(errSecNoSuchAttr);
-
-       return rit->second;
-}
-
-CssmDbAttributeInfo
-KeychainSchemaImpl::attributeInfoFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const
-{
-       CSSM_DB_ATTRIBUTE_INFO info;
-       info.AttributeFormat = attributeFormatFor(recordType, attributeId);
-       info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
-       info.Label.AttributeID = attributeId;
-
-       return info;
-}
-
-void
-KeychainSchemaImpl::getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, SecKeychainAttributeInfo **Info) const
-{
-       const RelationInfoMap &rmap = relationInfoMapFor(recordType);
-
-       SecKeychainAttributeInfo *theList=reinterpret_cast<SecKeychainAttributeInfo *>(malloc(sizeof(SecKeychainAttributeInfo)));
-       
-       UInt32 capacity=rmap.size();
-       UInt32 *tagBuf=reinterpret_cast<UInt32 *>(malloc(capacity*sizeof(UInt32)));
-       UInt32 *formatBuf=reinterpret_cast<UInt32 *>(malloc(capacity*sizeof(UInt32)));
-       UInt32 i=0;
-       
-       
-       for (RelationInfoMap::const_iterator rit = rmap.begin(); rit != rmap.end(); ++rit)
-       {
-               if (i>=capacity)
-               {
-                       capacity *= 2;
-                       if (capacity <= i) capacity = i + 1;
-                       tagBuf=reinterpret_cast<UInt32 *>(realloc(tagBuf, (capacity*sizeof(UInt32))));
-                       formatBuf=reinterpret_cast<UInt32 *>(realloc(tagBuf, (capacity*sizeof(UInt32))));
-               }
-               tagBuf[i]=rit->first;
-               formatBuf[i++]=rit->second;
-       }
-       
-       theList->count=i;
-       theList->tag=tagBuf;
-       theList->format=formatBuf;
-       *Info=theList;          
-}
-
-
-const CssmAutoDbRecordAttributeInfo &
-KeychainSchemaImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) const
-{
-       PrimaryKeyInfoMap::const_iterator it;
-       it = mPrimaryKeyInfoMap.find(recordType);
-       
-       if (it == mPrimaryKeyInfoMap.end())
-               MacOSError::throwMe(errSecNoSuchClass); // @@@ Not really but whatever.
-
-       return *it->second;
-}
-
-bool
-KeychainSchemaImpl::operator <(const KeychainSchemaImpl &other) const
-{
-       return mDatabaseInfoMap < other.mDatabaseInfoMap;
-}
-
-bool
-KeychainSchemaImpl::operator ==(const KeychainSchemaImpl &other) const
-{
-       return mDatabaseInfoMap == other.mDatabaseInfoMap;
-}
-
-
-//
-// KeychainImpl
-//
-KeychainImpl::KeychainImpl(const Db &db)
-: mDb(db)
-{
-}
-
-KeychainImpl::~KeychainImpl() throw()
-{
-       globals().storageManager.removeKeychain(dLDbIdentifier(), this);
-}
-
-bool
-KeychainImpl::operator ==(const KeychainImpl &keychain) const
-{
-       return dLDbIdentifier() == keychain.dLDbIdentifier();
-}
-
-KCCursor
-KeychainImpl::createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList)
-{
-       StorageManager::KeychainList keychains;
-       keychains.push_back(Keychain(this));
-       return KCCursor(keychains, itemClass, attrList);
-}
-
-KCCursor
-KeychainImpl::createCursor(const SecKeychainAttributeList *attrList)
-{
-       StorageManager::KeychainList keychains;
-       keychains.push_back(Keychain(this));
-       return KCCursor(keychains, attrList);
-}
-
-void
-KeychainImpl::create(UInt32 passwordLength, const void *inPassword)
-{
-       if (!inPassword)
-       {
-               create();
-               return;
-       }
-
-       CssmAllocator &alloc = CssmAllocator::standard();
-        
-       // @@@ Share this instance
-
-       const CssmData password(const_cast<void *>(inPassword), passwordLength);
-       AclFactory::PasswordChangeCredentials pCreds (password, alloc);
-       AclFactory::AnyResourceContext rcc(pCreds);
-       create(&rcc);
-}
-
-void KeychainImpl::create(ConstStringPtr inPassword)
-{
-    if ( inPassword )
-        create(static_cast<UInt32>(inPassword[0]), &inPassword[1]);
-    else
-        create();
-}
-
-void
-KeychainImpl::create()
-{
-       AclFactory aclFactory;
-       AclFactory::AnyResourceContext rcc(aclFactory.unlockCred());
-       create(&rcc);
-}
-
-void
-KeychainImpl::create(const ResourceControlContext *rcc)
-{
-       mDb->dbInfo(&Schema::DBInfo); // Set the schema (to force a create)
-       mDb->resourceControlContext(rcc);
-    try
-    {
-        mDb->create();
-    }
-    catch (...)
-    {
-               mDb->resourceControlContext(NULL);
-        mDb->dbInfo(NULL); // Clear the schema (to not break an open call later)
-        throw;
-    }
-       mDb->resourceControlContext(NULL);
-       mDb->dbInfo(NULL); // Clear the schema (to not break an open call later)
-       globals().storageManager.created(Keychain(this));
-
-    KCEventNotifier::PostKeychainEvent (kSecKeychainListChangedEvent, this, NULL);
-}
-
-void
-KeychainImpl::open()
-{
-       mDb->open();
-}
-
-void
-KeychainImpl::lock()
-{
-       mDb->lock();
-}
-
-void
-KeychainImpl::unlock()
-{
-       mDb->unlock();
-}
-
-void
-KeychainImpl::unlock(const CssmData &password)
-{
-       mDb->unlock(password);
-}
-
-void
-KeychainImpl::unlock(ConstStringPtr password)
-{
-       if (password)
-       {
-               const CssmData data(const_cast<unsigned char *>(&password[1]), password[0]);
-               unlock(data);
-       }
-       else
-               unlock();
-}
-
-void
-KeychainImpl::getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep)
-{
-       mDb->getSettings(outIdleTimeOut, outLockOnSleep);
-}
-
-void
-KeychainImpl::setSettings(uint32 inIdleTimeOut, bool inLockOnSleep)
-{
-       mDb->setSettings(inIdleTimeOut, inLockOnSleep);
-}
-void 
-KeychainImpl::changePassphrase(UInt32 oldPasswordLength, const void *oldPassword,
-       UInt32 newPasswordLength, const void *newPassword)
-{
-       // @@@ When AutoCredentials is actually finished we should no logner use a tracking allocator.
-       TrackingAllocator allocator(CssmAllocator::standard());
-       AutoCredentials cred = AutoCredentials(allocator);
-       if (oldPassword)
-       {
-               const CssmData &oldPass = *new(allocator) CssmData(const_cast<void *>(oldPassword), oldPasswordLength);
-               TypedList &oldList = *new(allocator) TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK);
-               oldList.append(new(allocator) ListElement(CSSM_SAMPLE_TYPE_PASSWORD));
-               oldList.append(new(allocator) ListElement(oldPass));
-               cred += oldList;
-       }
-
-       if (newPassword)
-       {
-               const CssmData &newPass = *new(allocator) CssmData(const_cast<void *>(newPassword), newPasswordLength);
-               TypedList &newList = *new(allocator) TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK);
-               newList.append(new(allocator) ListElement(CSSM_SAMPLE_TYPE_PASSWORD));
-               newList.append(new(allocator) ListElement(newPass));
-               cred += newList;
-       }
-
-       mDb->changePassphrase(&cred);
-}
-
-void
-KeychainImpl::changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword)
-{
-       const void *oldPtr, *newPtr;
-       UInt32 oldLen, newLen;
-       if (oldPassword)
-       {
-               oldLen = oldPassword[0];
-               oldPtr = oldPassword + 1;
-       }
-       else
-       {
-               oldLen = 0;
-               oldPtr = NULL;
-       }
-
-       if (newPassword)
-       {
-               newLen = newPassword[0];
-               newPtr = newPassword + 1;
-       }
-       else
-       {
-               newLen = 0;
-               newPtr = NULL;
-       }
-
-       changePassphrase(oldLen, oldPtr, newLen, newPtr);
-}
-
-void
-KeychainImpl::authenticate(const CSSM_ACCESS_CREDENTIALS *cred)
-{
-       // @@@ This should do an authenticate which is not the same as unlock.
-       if (!exists())
-               MacOSError::throwMe(errSecNoSuchKeychain);
-
-       MacOSError::throwMe(unimpErr);
-}
-
-UInt32
-KeychainImpl::status() const
-{
-       // @@@ We should figure out the read/write status though a DL passthrough or some other way.
-       // @@@ Also should locked be unlocked read only or just read-only?
-       return (mDb->isLocked() ? 0 : kSecUnlockStateStatus | kSecWritePermStatus) | kSecReadPermStatus;
-}
-
-bool
-KeychainImpl::exists()
-{
-       bool exists = true;
-       try
-       {
-               open();
-               // Ok to leave the mDb open since it will get closed when it goes away.
-       }
-       catch (const CssmError &e)
-       {
-               if (e.cssmError() != CSSMERR_DL_DATASTORE_DOESNOT_EXIST)
-                       throw;
-               exists = false;
-       }
-
-       return exists;
-}
-
-bool
-KeychainImpl::isActive() const
-{
-       return mDb->isActive();
-}
-
-void
-KeychainImpl::add(Item &inItem)
-{
-       Keychain keychain(this);
-       PrimaryKey primaryKey = inItem->add(keychain);
-       {
-               StLock<Mutex> _(mDbItemMapLock);
-               mDbItemMap[primaryKey] = inItem.get();
-       }
-
-    KCEventNotifier::PostKeychainEvent(kSecAddEvent, this, inItem);
-}
-
-void
-KeychainImpl::didUpdate(ItemImpl *inItemImpl, PrimaryKey &oldPK,
-                                               PrimaryKey &newPK)
-{
-       // Make sure we only hold mDbItemMapLock as long as we need to.
-       {
-               StLock<Mutex> _(mDbItemMapLock);
-               DbItemMap::iterator it = mDbItemMap.find(oldPK);
-               if (it != mDbItemMap.end() && it->second == inItemImpl)
-                       mDbItemMap.erase(it);
-               mDbItemMap[newPK] = inItemImpl;
-       }
-
-    KCEventNotifier::PostKeychainEvent( kSecUpdateEvent, this, inItemImpl );
-}
-
-void
-KeychainImpl::deleteItem(Item &inoutItem)
-{
-       // item must be persistant.
-       if (!inoutItem->isPersistant())
-               MacOSError::throwMe(errSecInvalidItemRef);
-
-       DbUniqueRecord uniqueId = inoutItem->dbUniqueRecord();
-       PrimaryKey primaryKey = inoutItem->primaryKey();
-       uniqueId->deleteRecord();
-
-       // Don't kill the ref or clear the Item() since this potentially
-       // messes up things for the receiver of the kSecDeleteEvent notification.
-       //inoutItem->killRef();
-       //inoutItem = Item();
-
-    // Post the notification for the item deletion with
-       // the primaryKey obtained when the item still existed
-       KCEventNotifier::PostKeychainEvent(kSecDeleteEvent, dLDbIdentifier(), primaryKey);
-}
-
-
-CssmClient::CSP
-KeychainImpl::csp()
-{
-       if (!mDb->dl()->subserviceMask() & CSSM_SERVICE_CSP)
-               MacOSError::throwMe(errSecInvalidKeychain);
-
-       SSDb ssDb(safe_cast<SSDbImpl *>(&(*mDb)));
-       return ssDb->csp();
-}
-
-PrimaryKey
-KeychainImpl::makePrimaryKey(CSSM_DB_RECORDTYPE recordType, DbUniqueRecord &uniqueId)
-{
-       DbAttributes primaryKeyAttrs(uniqueId->database());
-       primaryKeyAttrs.recordType(recordType);
-       gatherPrimaryKeyAttributes(primaryKeyAttrs);
-       uniqueId->get(&primaryKeyAttrs, NULL);
-       return PrimaryKey(primaryKeyAttrs);
-}
-
-const CssmAutoDbRecordAttributeInfo &
-KeychainImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType)
-{
-       try {
-               return keychainSchema()->primaryKeyInfosFor(recordType);
-       } catch (const CssmCommonError &error) {
-               switch (error.cssmError()) {
-               case errSecNoSuchClass:
-               case CSSMERR_DL_INVALID_RECORDTYPE:
-                       resetSchema();
-                       return keychainSchema()->primaryKeyInfosFor(recordType);
-               default:
-                       throw;
-               }
-       }
-}
-
-void KeychainImpl::gatherPrimaryKeyAttributes(DbAttributes& primaryKeyAttrs)
-{
-       const CssmAutoDbRecordAttributeInfo &infos =
-               primaryKeyInfosFor(primaryKeyAttrs.recordType());
-
-       // @@@ fix this to not copy info.               
-       for (uint32 i = 0; i < infos.size(); i++)
-               primaryKeyAttrs.add(infos.at(i));
-}
-
-Item
-KeychainImpl::item(const PrimaryKey& primaryKey)
-{
-       // @@@ This retry code isn't really the right way to do this,
-       // we need to redo the locking structure here in the future.
-       bool tried = false;
-       for (;;)
-       {
-               {
-                       StLock<Mutex> _(mDbItemMapLock);
-                       DbItemMap::iterator it = mDbItemMap.find(primaryKey);
-                       if (it != mDbItemMap.end())
-                       {
-                               return Item(it->second);
-                       }
-               }
-
-               try
-               {
-                       // Create an item with just a primary key
-                       return Item(this, primaryKey);
-               }
-               catch (const MacOSError &e)
-               {
-                       if (tried || e.osStatus() != errSecDuplicateItem)
-                               throw;
-                       tried = true;
-               }
-       }
-}
-
-Item
-KeychainImpl::item(CSSM_DB_RECORDTYPE recordType, DbUniqueRecord &uniqueId)
-{
-       PrimaryKey primaryKey = makePrimaryKey(recordType, uniqueId);
-       {
-               StLock<Mutex> _(mDbItemMapLock);
-               DbItemMap::iterator it = mDbItemMap.find(primaryKey);
-               if (it != mDbItemMap.end())
-               {
-                       return Item(it->second);
-               }
-       }
-
-       // Create a new item
-    return Item(this, primaryKey, uniqueId);
-}
-
-KeychainSchema
-KeychainImpl::keychainSchema()
-{
-       if (!mKeychainSchema)
-       {
-               // @@@ Use cache in storageManager
-               mKeychainSchema = KeychainSchema(mDb);
-       }
-
-       return mKeychainSchema;
-}
-
-void KeychainImpl::resetSchema()
-{
-       mKeychainSchema = NULL; // re-fetch it from db next time
-}
-
-
-// Called from DbItemImpl's constructor (so it is only paritally constructed), add it to the map. 
-void
-KeychainImpl::addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl)
-{
-       StLock<Mutex> _(mDbItemMapLock);
-       DbItemMap::iterator it = mDbItemMap.find(primaryKey);
-       if (it != mDbItemMap.end())
-       {
-               // @@@ There is a race condition here when being called in multiple threads
-               // We might have added an item using add and received a notification at the same time
-               //assert(true);
-               MacOSError::throwMe(errSecDuplicateItem);
-               //mDbItemMap.erase(it);
-               // @@@ What to do here?
-       }
-
-       mDbItemMap.insert(DbItemMap::value_type(primaryKey, dbItemImpl));
-}
-
-void
-KeychainImpl::didDeleteItem(const ItemImpl *inItemImpl)
-{
-       // Sent sent by CCallbackMgr.
-    secdebug("kcnotify", "%p notified that item %p was deleted", this, inItemImpl);
-       PrimaryKey primaryKey = inItemImpl->primaryKey();
-       StLock<Mutex> _(mDbItemMapLock);
-       DbItemMap::iterator it = mDbItemMap.find(primaryKey);
-       if (it != mDbItemMap.end())
-               mDbItemMap.erase(it);
-}
-
-void
-KeychainImpl::removeItem(const PrimaryKey &primaryKey, const ItemImpl *inItemImpl)
-{
-       // Sent from DbItemImpl's destructor, remove it from the map. 
-       StLock<Mutex> _(mDbItemMapLock);
-       DbItemMap::iterator it = mDbItemMap.find(primaryKey);
-       if (it != mDbItemMap.end() && it->second == inItemImpl)
-               mDbItemMap.erase(it);
-}
-
-void
-KeychainImpl::getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info)
-{
-       try {
-               keychainSchema()->getAttributeInfoForRecordType(itemID, Info);
-       } catch (const CssmCommonError &error) {
-               switch (error.cssmError()) {
-               case errSecNoSuchClass:
-               case CSSMERR_DL_INVALID_RECORDTYPE:
-                       resetSchema();
-                       keychainSchema()->getAttributeInfoForRecordType(itemID, Info);
-               default:
-                       throw;
-               }
-       }
-}
-
-void 
-KeychainImpl::freeAttributeInfo(SecKeychainAttributeInfo *Info)
-{
-       free(Info->tag);
-       free(Info->format);
-       free(Info);
-}
-
-CssmDbAttributeInfo
-KeychainImpl::attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag)
-{
-       try {
-               return keychainSchema()->attributeInfoFor(recordType, tag);
-       } catch (const CssmCommonError &error) {
-               switch (error.cssmError()) {
-               case errSecNoSuchClass:
-               case CSSMERR_DL_INVALID_RECORDTYPE:
-                       resetSchema();
-                       return keychainSchema()->attributeInfoFor(recordType, tag);
-               default:
-                       throw;
-               }
-       }
-
-}
-
-Keychain
-Keychain::optional(SecKeychainRef handle)
-{
-       if (handle)
-               return KeychainImpl::required(handle);
-       else
-               return globals().storageManager.defaultKeychain();
-}
-