X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/bac41a7b9a0a9254fa30f8bb6e6038ab71a483e2..9a27adb241486ab7597ffaea2b5613cd3d8e1f60:/Keychain/Keychains.cpp diff --git a/Keychain/Keychains.cpp b/Keychain/Keychains.cpp index 085b62f9..ae053cf8 100644 --- a/Keychain/Keychains.cpp +++ b/Keychain/Keychains.cpp @@ -31,7 +31,8 @@ #include #include #include - +#include +#include using namespace KeychainCore; using namespace CssmClient; @@ -71,7 +72,8 @@ KeychainSchemaImpl::KeychainSchemaImpl(const Db &db) RelationInfoMap &rim = mDatabaseInfoMap[relationID]; while (attributes->next(&attributeRecord, NULL, uniqueId)) { - if(CSSM_DB_ATTRIBUTE_FORMAT(attributeRecord.at(2))==CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER) + // @@@ 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); } @@ -104,60 +106,64 @@ KeychainSchemaImpl::~KeychainSchemaImpl() for_each_map_delete(mPrimaryKeyInfoMap.begin(), mPrimaryKeyInfoMap.end()); } -CSSM_DB_ATTRIBUTE_FORMAT -KeychainSchemaImpl::attributeFormatFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const +const KeychainSchemaImpl::RelationInfoMap & +KeychainSchemaImpl::relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const { - DatabaseInfoMap::const_iterator dit = mDatabaseInfoMap.find(recordType); if (dit == mDatabaseInfoMap.end()) MacOSError::throwMe(errSecNoSuchClass); - RelationInfoMap::const_iterator rit = dit->second.find(attributeId); - if (dit == dit->second.end()) + 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::attributeInfoForTag(UInt32 tag) +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; - for(DatabaseInfoMap::const_iterator dit = mDatabaseInfoMap.begin(); dit != mDatabaseInfoMap.end(); ++dit) - { - for(RelationInfoMap::const_iterator rit = dit->second.begin(); rit != dit->second.end(); ++rit) - { - if(rit->first==tag) - { - info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER; - info.Label.AttributeID = rit->first; - info.AttributeFormat = rit->second; - return info; - } - } - } return info; } void -KeychainSchemaImpl::getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, SecKeychainAttributeInfo **Info) +KeychainSchemaImpl::getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, SecKeychainAttributeInfo **Info) const { - DatabaseInfoMap::const_iterator dit = mDatabaseInfoMap.find(recordType); - if (dit == mDatabaseInfoMap.end()) - MacOSError::throwMe(errSecNoSuchClass); + const RelationInfoMap &rmap = relationInfoMapFor(recordType); SecKeychainAttributeInfo *theList=reinterpret_cast(malloc(sizeof(SecKeychainAttributeInfo))); - UInt32 capacity=32; + UInt32 capacity=rmap.size(); UInt32 *tagBuf=reinterpret_cast(malloc(capacity*sizeof(UInt32))); UInt32 *formatBuf=reinterpret_cast(malloc(capacity*sizeof(UInt32))); UInt32 i=0; - for(RelationInfoMap::const_iterator rit = dit->second.begin(); rit != dit->second.end(); ++rit) + + for (RelationInfoMap::const_iterator rit = rmap.begin(); rit != rmap.end(); ++rit) { - if(i>=capacity) + if (i>=capacity) { - capacity*=2; + capacity *= 2; + if (capacity <= i) capacity = i + 1; tagBuf=reinterpret_cast(realloc(tagBuf, (capacity*sizeof(UInt32)))); formatBuf=reinterpret_cast(realloc(tagBuf, (capacity*sizeof(UInt32)))); } @@ -173,14 +179,11 @@ KeychainSchemaImpl::getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, const CssmAutoDbRecordAttributeInfo & -KeychainSchemaImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) +KeychainSchemaImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) const { - PrimaryKeyInfoMap::iterator it; + PrimaryKeyInfoMap::const_iterator it; it = mPrimaryKeyInfoMap.find(recordType); - // if the primary key attributes have already been determined, - // return the cached results - if (it == mPrimaryKeyInfoMap.end()) MacOSError::throwMe(errSecNoSuchClass); // @@@ Not really but whatever. @@ -208,20 +211,31 @@ KeychainImpl::KeychainImpl(const Db &db) { } -KeychainImpl::~KeychainImpl() +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) { - return KCCursor(DbCursor(mDb), itemClass, attrList); + StorageManager::KeychainList keychains; + keychains.push_back(Keychain(this)); + return KCCursor(keychains, itemClass, attrList); } KCCursor KeychainImpl::createCursor(const SecKeychainAttributeList *attrList) { - return KCCursor(DbCursor(mDb), attrList); + StorageManager::KeychainList keychains; + keychains.push_back(Keychain(this)); + return KCCursor(keychains, attrList); } void @@ -234,22 +248,12 @@ KeychainImpl::create(UInt32 passwordLength, const void *inPassword) } CssmAllocator &alloc = CssmAllocator::standard(); + // @@@ Share this instance - KeychainAclFactory aclFactory(alloc); - // @@@ This leaks the returned credentials const CssmData password(const_cast(inPassword), passwordLength); - const AccessCredentials *cred = aclFactory.passwordChangeCredentials(password); - - // @@@ Create a nice wrapper for building the default AclEntryPrototype. - TypedList subject(alloc, CSSM_ACL_SUBJECT_TYPE_ANY); - AclEntryPrototype protoType(subject); - AuthorizationGroup &authGroup = protoType.authorization(); - CSSM_ACL_AUTHORIZATION_TAG tag = CSSM_ACL_AUTHORIZATION_ANY; - authGroup.NumberOfAuthTags = 1; - authGroup.AuthTags = &tag; - - const ResourceControlContext rcc(protoType, const_cast(cred)); + AclFactory::PasswordChangeCredentials pCreds (password, alloc); + AclFactory::AnyResourceContext rcc(pCreds); create(&rcc); } @@ -264,21 +268,8 @@ void KeychainImpl::create(ConstStringPtr inPassword) void KeychainImpl::create() { - CssmAllocator &alloc = CssmAllocator::standard(); - // @@@ Share this instance - KeychainAclFactory aclFactory(alloc); - - const AccessCredentials *cred = aclFactory.keychainPromptUnlockCredentials(); - - // @@@ Create a nice wrapper for building the default AclEntryPrototype. - TypedList subject(alloc, CSSM_ACL_SUBJECT_TYPE_ANY); - AclEntryPrototype protoType(subject); - AuthorizationGroup &authGroup = protoType.authorization(); - CSSM_ACL_AUTHORIZATION_TAG tag = CSSM_ACL_AUTHORIZATION_ANY; - authGroup.NumberOfAuthTags = 1; - authGroup.AuthTags = &tag; - - const ResourceControlContext rcc(protoType, const_cast(cred)); + AclFactory aclFactory; + AclFactory::AnyResourceContext rcc(aclFactory.unlockCred()); create(&rcc); } @@ -300,6 +291,8 @@ KeychainImpl::create(const ResourceControlContext *rcc) 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 @@ -422,7 +415,7 @@ 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 | kSecWrPermStatus) | kSecRdPermStatus; + return (mDb->isLocked() ? 0 : kSecUnlockStateStatus | kSecWritePermStatus) | kSecReadPermStatus; } bool @@ -453,11 +446,11 @@ KeychainImpl::isActive() const void KeychainImpl::add(Item &inItem) { - PrimaryKey primaryKey = inItem->add(this); + Keychain keychain(this); + PrimaryKey primaryKey = inItem->add(keychain); { StLock _(mDbItemMapLock); - // Use &* to get the item's Impl. - mDbItemMap[primaryKey] = &*inItem; + mDbItemMap[primaryKey] = inItem.get(); } KCEventNotifier::PostKeychainEvent(kSecAddEvent, this, inItem); @@ -500,6 +493,17 @@ KeychainImpl::deleteItem(Item &inoutItem) KCEventNotifier::PostKeychainEvent(kSecDeleteEvent, dLDbIdentifier(), primaryKey); } + +CssmClient::CSP +KeychainImpl::csp() +{ + if (!mDb->dl()->subserviceMask() & CSSM_SERVICE_CSP) + MacOSError::throwMe(errSecInvalidKeychain); + + SSDb ssDb(safe_cast(&(*mDb))); + return ssDb->csp(); +} + PrimaryKey KeychainImpl::makePrimaryKey(CSSM_DB_RECORDTYPE recordType, DbUniqueRecord &uniqueId) { @@ -513,7 +517,18 @@ KeychainImpl::makePrimaryKey(CSSM_DB_RECORDTYPE recordType, DbUniqueRecord &uniq const CssmAutoDbRecordAttributeInfo & KeychainImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) { - return keychainSchema()->primaryKeyInfosFor(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) @@ -529,17 +544,32 @@ void KeychainImpl::gatherPrimaryKeyAttributes(DbAttributes& primaryKeyAttrs) 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 _(mDbItemMapLock); - DbItemMap::iterator it = mDbItemMap.find(primaryKey); - if (it != mDbItemMap.end()) { - return Item(it->second); + StLock _(mDbItemMapLock); + DbItemMap::iterator it = mDbItemMap.find(primaryKey); + if (it != mDbItemMap.end()) + { + return Item(it->second); + } } - } - // Create an item with just a primary key - return Item(this, primaryKey); + 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 @@ -571,6 +601,12 @@ KeychainImpl::keychainSchema() 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) @@ -582,7 +618,7 @@ KeychainImpl::addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl) // @@@ 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); - throw errSecDuplicateItem; + MacOSError::throwMe(errSecDuplicateItem); //mDbItemMap.erase(it); // @@@ What to do here? } @@ -590,6 +626,18 @@ KeychainImpl::addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl) 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 _(mDbItemMapLock); + DbItemMap::iterator it = mDbItemMap.find(primaryKey); + if (it != mDbItemMap.end()) + mDbItemMap.erase(it); +} + void KeychainImpl::removeItem(const PrimaryKey &primaryKey, const ItemImpl *inItemImpl) { @@ -603,7 +651,18 @@ KeychainImpl::removeItem(const PrimaryKey &primaryKey, const ItemImpl *inItemImp void KeychainImpl::getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info) { - keychainSchema()->getAttributeInfoForRecordType(itemID, 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 @@ -615,9 +674,20 @@ KeychainImpl::freeAttributeInfo(SecKeychainAttributeInfo *Info) } CssmDbAttributeInfo -KeychainImpl::attributeInfoForTag(UInt32 tag) -{ - return keychainSchema()->attributeInfoForTag(tag); +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; + } + } } @@ -625,8 +695,8 @@ Keychain Keychain::optional(SecKeychainRef handle) { if (handle) - return KeychainRef::required(handle); + return KeychainImpl::required(handle); else - return globals().defaultKeychain; + return globals().storageManager.defaultKeychain(); }