]> git.saurik.com Git - apple/security.git/blame - Keychain/Keychains.cpp
Security-54.1.3.tar.gz
[apple/security.git] / Keychain / Keychains.cpp
CommitLineData
bac41a7b
A
1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// Keychains.cpp
21//
22
23#include "Keychains.h"
24#include "KCEventNotifier.h"
25
26#include "Item.h"
27#include "KCCursor.h"
28#include "Globals.h"
29#include "Schema.h"
30#include <Security/keychainacl.h>
31#include <Security/cssmacl.h>
32#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
33#include <Security/cssmdb.h>
29654253
A
34#include <Security/trackingallocator.h>
35#include <Security/SecCFTypes.h>
bac41a7b
A
36
37using namespace KeychainCore;
38using namespace CssmClient;
39
40
41//
42// KeychainSchemaImpl
43//
44KeychainSchemaImpl::KeychainSchemaImpl(const Db &db)
45{
46 DbCursor relations(db);
47 relations->recordType(CSSM_DL_DB_SCHEMA_INFO);
48 DbAttributes relationRecord(db, 1);
49 relationRecord.add(Schema::RelationID);
50 DbUniqueRecord outerUniqueId(db);
51
52 while (relations->next(&relationRecord, NULL, outerUniqueId))
53 {
54 DbUniqueRecord uniqueId(db);
55
56 uint32 relationID = relationRecord.at(0);
57 if (CSSM_DB_RECORDTYPE_SCHEMA_START <= relationID && relationID < CSSM_DB_RECORDTYPE_SCHEMA_END)
58 continue;
59
60 // Create a cursor on the SCHEMA_ATTRIBUTES table for records with RelationID == relationID
61 DbCursor attributes(db);
62 attributes->recordType(CSSM_DL_DB_SCHEMA_ATTRIBUTES);
63 attributes->add(CSSM_DB_EQUAL, Schema::RelationID, relationID);
64
65 // Set up a record for retriving the SCHEMA_ATTRIBUTES
66 DbAttributes attributeRecord(db, 2);
67 attributeRecord.add(Schema::AttributeFormat);
68 attributeRecord.add(Schema::AttributeID);
69 attributeRecord.add(Schema::AttributeNameFormat);
70
71
72 RelationInfoMap &rim = mDatabaseInfoMap[relationID];
73 while (attributes->next(&attributeRecord, NULL, uniqueId))
74 {
29654253
A
75 // @@@ this if statement was blocking tags of different naming conventions
76 //if(CSSM_DB_ATTRIBUTE_FORMAT(attributeRecord.at(2))==CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER)
bac41a7b
A
77 rim[attributeRecord.at(1)] = attributeRecord.at(0);
78 }
79
80 // Create a cursor on the CSSM_DL_DB_SCHEMA_INDEXES table for records with RelationID == relationID
81 DbCursor indexes(db);
82 indexes->recordType(CSSM_DL_DB_SCHEMA_INDEXES);
83 indexes->conjunctive(CSSM_DB_AND);
84 indexes->add(CSSM_DB_EQUAL, Schema::RelationID, relationID);
85 indexes->add(CSSM_DB_EQUAL, Schema::IndexType, uint32(CSSM_DB_INDEX_UNIQUE));
86
87 // Set up a record for retriving the SCHEMA_INDEXES
88 DbAttributes indexRecord(db, 1);
89 indexRecord.add(Schema::AttributeID);
90
91 CssmAutoDbRecordAttributeInfo &infos = *new CssmAutoDbRecordAttributeInfo();
92 mPrimaryKeyInfoMap.insert(PrimaryKeyInfoMap::value_type(relationID, &infos));
93 infos.DataRecordType = relationID;
94 while (indexes->next(&indexRecord, NULL, uniqueId))
95 {
96 CssmDbAttributeInfo &info = infos.add();
97 info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
98 info.Label.AttributeID = indexRecord.at(0);
99 info.AttributeFormat = rim[info.Label.AttributeID]; // @@@ Might insert bogus value if DB is corrupt
100 }
101 }
102}
103
104KeychainSchemaImpl::~KeychainSchemaImpl()
105{
106 for_each_map_delete(mPrimaryKeyInfoMap.begin(), mPrimaryKeyInfoMap.end());
107}
108
29654253
A
109const KeychainSchemaImpl::RelationInfoMap &
110KeychainSchemaImpl::relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const
bac41a7b 111{
bac41a7b
A
112 DatabaseInfoMap::const_iterator dit = mDatabaseInfoMap.find(recordType);
113 if (dit == mDatabaseInfoMap.end())
114 MacOSError::throwMe(errSecNoSuchClass);
29654253
A
115 return dit->second;
116}
117
118bool
119KeychainSchemaImpl::hasAttribute(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const
120{
121 const RelationInfoMap &rmap = relationInfoMapFor(recordType);
122 RelationInfoMap::const_iterator rit = rmap.find(attributeId);
123 return rit != rmap.end();
124}
125
126CSSM_DB_ATTRIBUTE_FORMAT
127KeychainSchemaImpl::attributeFormatFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const
128{
129 const RelationInfoMap &rmap = relationInfoMapFor(recordType);
130 RelationInfoMap::const_iterator rit = rmap.find(attributeId);
131 if (rit == rmap.end())
bac41a7b
A
132 MacOSError::throwMe(errSecNoSuchAttr);
133
134 return rit->second;
135}
136
137CssmDbAttributeInfo
29654253 138KeychainSchemaImpl::attributeInfoFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const
bac41a7b
A
139{
140 CSSM_DB_ATTRIBUTE_INFO info;
29654253
A
141 info.AttributeFormat = attributeFormatFor(recordType, attributeId);
142 info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
143 info.Label.AttributeID = attributeId;
bac41a7b 144
bac41a7b
A
145 return info;
146}
147
148void
29654253 149KeychainSchemaImpl::getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, SecKeychainAttributeInfo **Info) const
bac41a7b 150{
29654253 151 const RelationInfoMap &rmap = relationInfoMapFor(recordType);
bac41a7b
A
152
153 SecKeychainAttributeInfo *theList=reinterpret_cast<SecKeychainAttributeInfo *>(malloc(sizeof(SecKeychainAttributeInfo)));
154
29654253 155 UInt32 capacity=rmap.size();
bac41a7b
A
156 UInt32 *tagBuf=reinterpret_cast<UInt32 *>(malloc(capacity*sizeof(UInt32)));
157 UInt32 *formatBuf=reinterpret_cast<UInt32 *>(malloc(capacity*sizeof(UInt32)));
158 UInt32 i=0;
159
29654253
A
160
161 for (RelationInfoMap::const_iterator rit = rmap.begin(); rit != rmap.end(); ++rit)
bac41a7b 162 {
29654253 163 if (i>=capacity)
bac41a7b 164 {
29654253
A
165 capacity *= 2;
166 if (capacity <= i) capacity = i + 1;
bac41a7b
A
167 tagBuf=reinterpret_cast<UInt32 *>(realloc(tagBuf, (capacity*sizeof(UInt32))));
168 formatBuf=reinterpret_cast<UInt32 *>(realloc(tagBuf, (capacity*sizeof(UInt32))));
169 }
170 tagBuf[i]=rit->first;
171 formatBuf[i++]=rit->second;
172 }
173
174 theList->count=i;
175 theList->tag=tagBuf;
176 theList->format=formatBuf;
177 *Info=theList;
178}
179
180
181const CssmAutoDbRecordAttributeInfo &
29654253 182KeychainSchemaImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) const
bac41a7b 183{
29654253 184 PrimaryKeyInfoMap::const_iterator it;
bac41a7b
A
185 it = mPrimaryKeyInfoMap.find(recordType);
186
bac41a7b
A
187 if (it == mPrimaryKeyInfoMap.end())
188 MacOSError::throwMe(errSecNoSuchClass); // @@@ Not really but whatever.
189
190 return *it->second;
191}
192
193bool
194KeychainSchemaImpl::operator <(const KeychainSchemaImpl &other) const
195{
196 return mDatabaseInfoMap < other.mDatabaseInfoMap;
197}
198
199bool
200KeychainSchemaImpl::operator ==(const KeychainSchemaImpl &other) const
201{
202 return mDatabaseInfoMap == other.mDatabaseInfoMap;
203}
204
205
206//
207// KeychainImpl
208//
209KeychainImpl::KeychainImpl(const Db &db)
210: mDb(db)
211{
212}
213
214KeychainImpl::~KeychainImpl()
215{
216}
217
29654253
A
218bool
219KeychainImpl::operator ==(const KeychainImpl &keychain) const
220{
221 return dLDbIdentifier() == keychain.dLDbIdentifier();
222}
223
bac41a7b
A
224KCCursor
225KeychainImpl::createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList)
226{
29654253
A
227 StorageManager::KeychainList keychains;
228 keychains.push_back(Keychain(this));
229 return KCCursor(keychains, itemClass, attrList);
bac41a7b
A
230}
231
232KCCursor
233KeychainImpl::createCursor(const SecKeychainAttributeList *attrList)
234{
29654253
A
235 StorageManager::KeychainList keychains;
236 keychains.push_back(Keychain(this));
237 return KCCursor(keychains, attrList);
bac41a7b
A
238}
239
240void
241KeychainImpl::create(UInt32 passwordLength, const void *inPassword)
242{
243 if (!inPassword)
244 {
245 create();
246 return;
247 }
248
249 CssmAllocator &alloc = CssmAllocator::standard();
29654253 250
bac41a7b 251 // @@@ Share this instance
bac41a7b 252
bac41a7b 253 const CssmData password(const_cast<void *>(inPassword), passwordLength);
29654253
A
254 AclFactory::PasswordChangeCredentials pCreds (password, alloc);
255 const AccessCredentials* aa = pCreds;
256
bac41a7b
A
257 // @@@ Create a nice wrapper for building the default AclEntryPrototype.
258 TypedList subject(alloc, CSSM_ACL_SUBJECT_TYPE_ANY);
259 AclEntryPrototype protoType(subject);
260 AuthorizationGroup &authGroup = protoType.authorization();
261 CSSM_ACL_AUTHORIZATION_TAG tag = CSSM_ACL_AUTHORIZATION_ANY;
262 authGroup.NumberOfAuthTags = 1;
263 authGroup.AuthTags = &tag;
264
29654253 265 const ResourceControlContext rcc(protoType, const_cast<AccessCredentials *>(aa));
bac41a7b
A
266 create(&rcc);
267}
268
269void KeychainImpl::create(ConstStringPtr inPassword)
270{
271 if ( inPassword )
272 create(static_cast<UInt32>(inPassword[0]), &inPassword[1]);
273 else
274 create();
275}
276
277void
278KeychainImpl::create()
279{
280 CssmAllocator &alloc = CssmAllocator::standard();
281 // @@@ Share this instance
29654253 282#ifdef OBSOLETE
bac41a7b
A
283 KeychainAclFactory aclFactory(alloc);
284
285 const AccessCredentials *cred = aclFactory.keychainPromptUnlockCredentials();
29654253
A
286#endif
287 AclFactory aclFactor;
288 const AccessCredentials *cred = aclFactor.unlockCred ();
289
bac41a7b
A
290 // @@@ Create a nice wrapper for building the default AclEntryPrototype.
291 TypedList subject(alloc, CSSM_ACL_SUBJECT_TYPE_ANY);
292 AclEntryPrototype protoType(subject);
293 AuthorizationGroup &authGroup = protoType.authorization();
294 CSSM_ACL_AUTHORIZATION_TAG tag = CSSM_ACL_AUTHORIZATION_ANY;
295 authGroup.NumberOfAuthTags = 1;
296 authGroup.AuthTags = &tag;
297
298 const ResourceControlContext rcc(protoType, const_cast<AccessCredentials *>(cred));
299 create(&rcc);
300}
301
302void
303KeychainImpl::create(const ResourceControlContext *rcc)
304{
305 mDb->dbInfo(&Schema::DBInfo); // Set the schema (to force a create)
306 mDb->resourceControlContext(rcc);
307 try
308 {
309 mDb->create();
310 }
311 catch (...)
312 {
313 mDb->resourceControlContext(NULL);
314 mDb->dbInfo(NULL); // Clear the schema (to not break an open call later)
315 throw;
316 }
317 mDb->resourceControlContext(NULL);
318 mDb->dbInfo(NULL); // Clear the schema (to not break an open call later)
319 globals().storageManager.created(Keychain(this));
320}
321
322void
323KeychainImpl::open()
324{
325 mDb->open();
326}
327
328void
329KeychainImpl::lock()
330{
331 mDb->lock();
332}
333
334void
335KeychainImpl::unlock()
336{
337 mDb->unlock();
338}
339
340void
341KeychainImpl::unlock(const CssmData &password)
342{
343 mDb->unlock(password);
344}
345
346void
347KeychainImpl::unlock(ConstStringPtr password)
348{
349 if (password)
350 {
351 const CssmData data(const_cast<unsigned char *>(&password[1]), password[0]);
352 unlock(data);
353 }
354 else
355 unlock();
356}
357
358void
359KeychainImpl::getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep)
360{
361 mDb->getSettings(outIdleTimeOut, outLockOnSleep);
362}
363
364void
365KeychainImpl::setSettings(uint32 inIdleTimeOut, bool inLockOnSleep)
366{
367 mDb->setSettings(inIdleTimeOut, inLockOnSleep);
368}
369void
370KeychainImpl::changePassphrase(UInt32 oldPasswordLength, const void *oldPassword,
371 UInt32 newPasswordLength, const void *newPassword)
372{
373 // @@@ When AutoCredentials is actually finished we should no logner use a tracking allocator.
374 TrackingAllocator allocator(CssmAllocator::standard());
375 AutoCredentials cred = AutoCredentials(allocator);
376 if (oldPassword)
377 {
378 const CssmData &oldPass = *new(allocator) CssmData(const_cast<void *>(oldPassword), oldPasswordLength);
379 TypedList &oldList = *new(allocator) TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK);
380 oldList.append(new(allocator) ListElement(CSSM_SAMPLE_TYPE_PASSWORD));
381 oldList.append(new(allocator) ListElement(oldPass));
382 cred += oldList;
383 }
384
385 if (newPassword)
386 {
387 const CssmData &newPass = *new(allocator) CssmData(const_cast<void *>(newPassword), newPasswordLength);
388 TypedList &newList = *new(allocator) TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK);
389 newList.append(new(allocator) ListElement(CSSM_SAMPLE_TYPE_PASSWORD));
390 newList.append(new(allocator) ListElement(newPass));
391 cred += newList;
392 }
393
394 mDb->changePassphrase(&cred);
395}
396
397void
398KeychainImpl::changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword)
399{
400 const void *oldPtr, *newPtr;
401 UInt32 oldLen, newLen;
402 if (oldPassword)
403 {
404 oldLen = oldPassword[0];
405 oldPtr = oldPassword + 1;
406 }
407 else
408 {
409 oldLen = 0;
410 oldPtr = NULL;
411 }
412
413 if (newPassword)
414 {
415 newLen = newPassword[0];
416 newPtr = newPassword + 1;
417 }
418 else
419 {
420 newLen = 0;
421 newPtr = NULL;
422 }
423
424 changePassphrase(oldLen, oldPtr, newLen, newPtr);
425}
426
427void
428KeychainImpl::authenticate(const CSSM_ACCESS_CREDENTIALS *cred)
429{
430 // @@@ This should do an authenticate which is not the same as unlock.
431 if (!exists())
432 MacOSError::throwMe(errSecNoSuchKeychain);
433
434 MacOSError::throwMe(unimpErr);
435}
436
437UInt32
438KeychainImpl::status() const
439{
440 // @@@ We should figure out the read/write status though a DL passthrough or some other way.
441 // @@@ Also should locked be unlocked read only or just read-only?
29654253 442 return (mDb->isLocked() ? 0 : kSecUnlockStateStatus | kSecWritePermStatus) | kSecReadPermStatus;
bac41a7b
A
443}
444
445bool
446KeychainImpl::exists()
447{
448 bool exists = true;
449 try
450 {
451 open();
452 // Ok to leave the mDb open since it will get closed when it goes away.
453 }
454 catch (const CssmError &e)
455 {
456 if (e.cssmError() != CSSMERR_DL_DATASTORE_DOESNOT_EXIST)
457 throw;
458 exists = false;
459 }
460
461 return exists;
462}
463
464bool
465KeychainImpl::isActive() const
466{
467 return mDb->isActive();
468}
469
470void
471KeychainImpl::add(Item &inItem)
472{
29654253
A
473 Keychain keychain(this);
474 PrimaryKey primaryKey = inItem->add(keychain);
bac41a7b
A
475 {
476 StLock<Mutex> _(mDbItemMapLock);
29654253 477 mDbItemMap[primaryKey] = inItem.get();
bac41a7b
A
478 }
479
480 KCEventNotifier::PostKeychainEvent(kSecAddEvent, this, inItem);
481}
482
483void
484KeychainImpl::didUpdate(ItemImpl *inItemImpl, PrimaryKey &oldPK,
485 PrimaryKey &newPK)
486{
487 // Make sure we only hold mDbItemMapLock as long as we need to.
488 {
489 StLock<Mutex> _(mDbItemMapLock);
490 DbItemMap::iterator it = mDbItemMap.find(oldPK);
491 if (it != mDbItemMap.end() && it->second == inItemImpl)
492 mDbItemMap.erase(it);
493 mDbItemMap[newPK] = inItemImpl;
494 }
495
496 KCEventNotifier::PostKeychainEvent( kSecUpdateEvent, this, inItemImpl );
497}
498
499void
500KeychainImpl::deleteItem(Item &inoutItem)
501{
502 // item must be persistant.
503 if (!inoutItem->isPersistant())
504 MacOSError::throwMe(errSecInvalidItemRef);
505
506 DbUniqueRecord uniqueId = inoutItem->dbUniqueRecord();
507 PrimaryKey primaryKey = inoutItem->primaryKey();
508 uniqueId->deleteRecord();
509
510 // Don't kill the ref or clear the Item() since this potentially
511 // messes up things for the receiver of the kSecDeleteEvent notification.
512 //inoutItem->killRef();
513 //inoutItem = Item();
514
515 // Post the notification for the item deletion with
516 // the primaryKey obtained when the item still existed
517 KCEventNotifier::PostKeychainEvent(kSecDeleteEvent, dLDbIdentifier(), primaryKey);
518}
519
29654253
A
520
521CssmClient::CSP
522KeychainImpl::csp()
523{
524 if (!mDb->dl()->subserviceMask() & CSSM_SERVICE_CSP)
525 MacOSError::throwMe(errSecInvalidKeychain);
526
527 SSDb ssDb(safe_cast<SSDbImpl *>(&(*mDb)));
528 return ssDb->csp();
529}
530
bac41a7b
A
531PrimaryKey
532KeychainImpl::makePrimaryKey(CSSM_DB_RECORDTYPE recordType, DbUniqueRecord &uniqueId)
533{
534 DbAttributes primaryKeyAttrs(uniqueId->database());
535 primaryKeyAttrs.recordType(recordType);
536 gatherPrimaryKeyAttributes(primaryKeyAttrs);
537 uniqueId->get(&primaryKeyAttrs, NULL);
538 return PrimaryKey(primaryKeyAttrs);
539}
540
541const CssmAutoDbRecordAttributeInfo &
542KeychainImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType)
543{
544 return keychainSchema()->primaryKeyInfosFor(recordType);
545}
546
547void KeychainImpl::gatherPrimaryKeyAttributes(DbAttributes& primaryKeyAttrs)
548{
549 const CssmAutoDbRecordAttributeInfo &infos =
550 primaryKeyInfosFor(primaryKeyAttrs.recordType());
551
552 // @@@ fix this to not copy info.
553 for (uint32 i = 0; i < infos.size(); i++)
554 primaryKeyAttrs.add(infos.at(i));
555}
556
557Item
558KeychainImpl::item(const PrimaryKey& primaryKey)
559{
560 {
561 StLock<Mutex> _(mDbItemMapLock);
562 DbItemMap::iterator it = mDbItemMap.find(primaryKey);
563 if (it != mDbItemMap.end())
564 {
565 return Item(it->second);
566 }
567 }
568
569 // Create an item with just a primary key
570 return Item(this, primaryKey);
571}
572
573Item
574KeychainImpl::item(CSSM_DB_RECORDTYPE recordType, DbUniqueRecord &uniqueId)
575{
576 PrimaryKey primaryKey = makePrimaryKey(recordType, uniqueId);
577 {
578 StLock<Mutex> _(mDbItemMapLock);
579 DbItemMap::iterator it = mDbItemMap.find(primaryKey);
580 if (it != mDbItemMap.end())
581 {
582 return Item(it->second);
583 }
584 }
585
586 // Create a new item
587 return Item(this, primaryKey, uniqueId);
588}
589
590KeychainSchema
591KeychainImpl::keychainSchema()
592{
593 if (!mKeychainSchema)
594 {
595 // @@@ Use cache in storageManager
596 mKeychainSchema = KeychainSchema(mDb);
597 }
598
599 return mKeychainSchema;
600}
601
602// Called from DbItemImpl's constructor (so it is only paritally constructed), add it to the map.
603void
604KeychainImpl::addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl)
605{
606 StLock<Mutex> _(mDbItemMapLock);
607 DbItemMap::iterator it = mDbItemMap.find(primaryKey);
608 if (it != mDbItemMap.end())
609 {
610 // @@@ There is a race condition here when being called in multiple threads
611 // We might have added an item using add and received a notification at the same time
612 //assert(true);
613 throw errSecDuplicateItem;
614 //mDbItemMap.erase(it);
615 // @@@ What to do here?
616 }
617
618 mDbItemMap.insert(DbItemMap::value_type(primaryKey, dbItemImpl));
619}
620
5a719ac8
A
621void
622KeychainImpl::didDeleteItem(const ItemImpl *inItemImpl)
623{
624 // Sent sent by CCallbackMgr.
625 debug("kcnotify", "%p notified that item %p was deleted", this, inItemImpl);
626 PrimaryKey primaryKey = inItemImpl->primaryKey();
627 StLock<Mutex> _(mDbItemMapLock);
628 DbItemMap::iterator it = mDbItemMap.find(primaryKey);
629 if (it != mDbItemMap.end())
630 mDbItemMap.erase(it);
631}
632
bac41a7b
A
633void
634KeychainImpl::removeItem(const PrimaryKey &primaryKey, const ItemImpl *inItemImpl)
635{
636 // Sent from DbItemImpl's destructor, remove it from the map.
637 StLock<Mutex> _(mDbItemMapLock);
638 DbItemMap::iterator it = mDbItemMap.find(primaryKey);
639 if (it != mDbItemMap.end() && it->second == inItemImpl)
640 mDbItemMap.erase(it);
641}
642
643void
644KeychainImpl::getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info)
645{
646 keychainSchema()->getAttributeInfoForRecordType(itemID, Info);
647}
648
649void
650KeychainImpl::freeAttributeInfo(SecKeychainAttributeInfo *Info)
651{
652 free(Info->tag);
653 free(Info->format);
654 free(Info);
655}
656
657CssmDbAttributeInfo
29654253 658KeychainImpl::attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag)
bac41a7b 659{
29654253 660 return keychainSchema()->attributeInfoFor(recordType, tag);
bac41a7b
A
661
662}
663
664Keychain
665Keychain::optional(SecKeychainRef handle)
666{
667 if (handle)
29654253 668 return gTypes().keychain.required(handle);
bac41a7b
A
669 else
670 return globals().defaultKeychain;
671}
672