]>
Commit | Line | Data |
---|---|---|
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 | |
37 | using namespace KeychainCore; | |
38 | using namespace CssmClient; | |
39 | ||
40 | ||
41 | // | |
42 | // KeychainSchemaImpl | |
43 | // | |
44 | KeychainSchemaImpl::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 | ||
104 | KeychainSchemaImpl::~KeychainSchemaImpl() | |
105 | { | |
106 | for_each_map_delete(mPrimaryKeyInfoMap.begin(), mPrimaryKeyInfoMap.end()); | |
107 | } | |
108 | ||
29654253 A |
109 | const KeychainSchemaImpl::RelationInfoMap & |
110 | KeychainSchemaImpl::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 | ||
118 | bool | |
119 | KeychainSchemaImpl::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 | ||
126 | CSSM_DB_ATTRIBUTE_FORMAT | |
127 | KeychainSchemaImpl::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 | ||
137 | CssmDbAttributeInfo | |
29654253 | 138 | KeychainSchemaImpl::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 | ||
148 | void | |
29654253 | 149 | KeychainSchemaImpl::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 | ||
181 | const CssmAutoDbRecordAttributeInfo & | |
29654253 | 182 | KeychainSchemaImpl::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 | ||
193 | bool | |
194 | KeychainSchemaImpl::operator <(const KeychainSchemaImpl &other) const | |
195 | { | |
196 | return mDatabaseInfoMap < other.mDatabaseInfoMap; | |
197 | } | |
198 | ||
199 | bool | |
200 | KeychainSchemaImpl::operator ==(const KeychainSchemaImpl &other) const | |
201 | { | |
202 | return mDatabaseInfoMap == other.mDatabaseInfoMap; | |
203 | } | |
204 | ||
205 | ||
206 | // | |
207 | // KeychainImpl | |
208 | // | |
209 | KeychainImpl::KeychainImpl(const Db &db) | |
210 | : mDb(db) | |
211 | { | |
212 | } | |
213 | ||
214 | KeychainImpl::~KeychainImpl() | |
215 | { | |
216 | } | |
217 | ||
29654253 A |
218 | bool |
219 | KeychainImpl::operator ==(const KeychainImpl &keychain) const | |
220 | { | |
221 | return dLDbIdentifier() == keychain.dLDbIdentifier(); | |
222 | } | |
223 | ||
bac41a7b A |
224 | KCCursor |
225 | KeychainImpl::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 | ||
232 | KCCursor | |
233 | KeychainImpl::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 | ||
240 | void | |
241 | KeychainImpl::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 | ||
269 | void KeychainImpl::create(ConstStringPtr inPassword) | |
270 | { | |
271 | if ( inPassword ) | |
272 | create(static_cast<UInt32>(inPassword[0]), &inPassword[1]); | |
273 | else | |
274 | create(); | |
275 | } | |
276 | ||
277 | void | |
278 | KeychainImpl::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 | ||
302 | void | |
303 | KeychainImpl::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 | ||
322 | void | |
323 | KeychainImpl::open() | |
324 | { | |
325 | mDb->open(); | |
326 | } | |
327 | ||
328 | void | |
329 | KeychainImpl::lock() | |
330 | { | |
331 | mDb->lock(); | |
332 | } | |
333 | ||
334 | void | |
335 | KeychainImpl::unlock() | |
336 | { | |
337 | mDb->unlock(); | |
338 | } | |
339 | ||
340 | void | |
341 | KeychainImpl::unlock(const CssmData &password) | |
342 | { | |
343 | mDb->unlock(password); | |
344 | } | |
345 | ||
346 | void | |
347 | KeychainImpl::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 | ||
358 | void | |
359 | KeychainImpl::getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep) | |
360 | { | |
361 | mDb->getSettings(outIdleTimeOut, outLockOnSleep); | |
362 | } | |
363 | ||
364 | void | |
365 | KeychainImpl::setSettings(uint32 inIdleTimeOut, bool inLockOnSleep) | |
366 | { | |
367 | mDb->setSettings(inIdleTimeOut, inLockOnSleep); | |
368 | } | |
369 | void | |
370 | KeychainImpl::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 | ||
397 | void | |
398 | KeychainImpl::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 | ||
427 | void | |
428 | KeychainImpl::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 | ||
437 | UInt32 | |
438 | KeychainImpl::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 | ||
445 | bool | |
446 | KeychainImpl::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 | ||
464 | bool | |
465 | KeychainImpl::isActive() const | |
466 | { | |
467 | return mDb->isActive(); | |
468 | } | |
469 | ||
470 | void | |
471 | KeychainImpl::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 | ||
483 | void | |
484 | KeychainImpl::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 | ||
499 | void | |
500 | KeychainImpl::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 | |
521 | CssmClient::CSP | |
522 | KeychainImpl::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 |
531 | PrimaryKey |
532 | KeychainImpl::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 | ||
541 | const CssmAutoDbRecordAttributeInfo & | |
542 | KeychainImpl::primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) | |
543 | { | |
544 | return keychainSchema()->primaryKeyInfosFor(recordType); | |
545 | } | |
546 | ||
547 | void 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 | ||
557 | Item | |
558 | KeychainImpl::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 | ||
573 | Item | |
574 | KeychainImpl::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 | ||
590 | KeychainSchema | |
591 | KeychainImpl::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. | |
603 | void | |
604 | KeychainImpl::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 |
621 | void |
622 | KeychainImpl::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 |
633 | void |
634 | KeychainImpl::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 | ||
643 | void | |
644 | KeychainImpl::getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info) | |
645 | { | |
646 | keychainSchema()->getAttributeInfoForRecordType(itemID, Info); | |
647 | } | |
648 | ||
649 | void | |
650 | KeychainImpl::freeAttributeInfo(SecKeychainAttributeInfo *Info) | |
651 | { | |
652 | free(Info->tag); | |
653 | free(Info->format); | |
654 | free(Info); | |
655 | } | |
656 | ||
657 | CssmDbAttributeInfo | |
29654253 | 658 | KeychainImpl::attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag) |
bac41a7b | 659 | { |
29654253 | 660 | return keychainSchema()->attributeInfoFor(recordType, tag); |
bac41a7b A |
661 | |
662 | } | |
663 | ||
664 | Keychain | |
665 | Keychain::optional(SecKeychainRef handle) | |
666 | { | |
667 | if (handle) | |
29654253 | 668 | return gTypes().keychain.required(handle); |
bac41a7b A |
669 | else |
670 | return globals().defaultKeychain; | |
671 | } | |
672 |