]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/Item.cpp
Security-55179.13.tar.gz
[apple/security.git] / libsecurity_keychain / lib / Item.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // Item.cpp
27 //
28
29 #include "Item.h"
30
31 #include "Certificate.h"
32 #include "KeyItem.h"
33 #include "ExtendedAttribute.h"
34
35 #include "Globals.h"
36 #include <security_cdsa_utilities/Schema.h>
37 #include "KCEventNotifier.h"
38 #include "cssmdatetime.h"
39 #include <security_cdsa_client/keychainacl.h>
40 #include <security_utilities/osxcode.h>
41 #include <security_utilities/trackingallocator.h>
42 #include <Security/SecKeychainItemPriv.h>
43 #include <Security/cssmapple.h>
44
45 #define SENDACCESSNOTIFICATIONS 1
46
47 //%%% schema indexes should be defined in Schema.h
48 #define APPLEDB_CSSM_PRINTNAME_ATTRIBUTE 1 /* schema index for label attribute of keys or certificates */
49 #define APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE 7 /* schema index for label attribute of password items */
50 #define IS_PASSWORD_ITEM_CLASS(X) ( (X) == kSecInternetPasswordItemClass || \
51 (X) == kSecGenericPasswordItemClass || \
52 (X) == kSecAppleSharePasswordItemClass ) ? 1 : 0
53
54 using namespace KeychainCore;
55 using namespace CSSMDateTimeUtils;
56
57 //
58 // ItemImpl
59 //
60
61 // NewItemImpl constructor
62 ItemImpl::ItemImpl(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, bool dontDoAttributes)
63 : mDbAttributes(new DbAttributes()),
64 mKeychain(NULL),
65 mDoNotEncrypt(false),
66 mInCache(false),
67 mMutex(Mutex::recursive)
68 {
69 if (length && data)
70 mData = new CssmDataContainer(data, length);
71
72 mDbAttributes->recordType(Schema::recordTypeFor(itemClass));
73
74 if (itemCreator)
75 mDbAttributes->add(Schema::attributeInfo(kSecCreatorItemAttr), itemCreator);
76 }
77
78 ItemImpl::ItemImpl(SecItemClass itemClass, SecKeychainAttributeList *attrList, UInt32 length, const void* data)
79 : mDbAttributes(new DbAttributes()),
80 mKeychain(NULL),
81 mDoNotEncrypt(false),
82 mInCache(false),
83 mMutex(Mutex::recursive)
84 {
85 if (length && data)
86 mData = new CssmDataContainer(data, length);
87
88
89 mDbAttributes->recordType(Schema::recordTypeFor(itemClass));
90
91 if(attrList)
92 {
93 for(UInt32 i=0; i < attrList->count; i++)
94 {
95 mDbAttributes->add(Schema::attributeInfo(attrList->attr[i].tag), CssmData(attrList->attr[i].data, attrList->attr[i].length));
96 }
97 }
98 }
99
100 // DbItemImpl constructor
101 ItemImpl::ItemImpl(const Keychain &keychain, const PrimaryKey &primaryKey, const DbUniqueRecord &uniqueId)
102 : mUniqueId(uniqueId), mKeychain(keychain), mPrimaryKey(primaryKey),
103 mDoNotEncrypt(false), mInCache(false),
104 mMutex(Mutex::recursive)
105 {
106 }
107
108 // PrimaryKey ItemImpl constructor
109 ItemImpl::ItemImpl(const Keychain &keychain, const PrimaryKey &primaryKey)
110 : mKeychain(keychain), mPrimaryKey(primaryKey), mDoNotEncrypt(false),
111 mInCache(false),
112 mMutex(Mutex::recursive)
113 {
114 }
115
116 ItemImpl* ItemImpl::make(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
117 {
118 ItemImpl* ii = new ItemImpl(keychain, primaryKey, uniqueId);
119 keychain->addItem(primaryKey, ii);
120 return ii;
121 }
122
123
124
125 ItemImpl* ItemImpl::make(const Keychain &keychain, const PrimaryKey &primaryKey)
126 {
127 ItemImpl* ii = new ItemImpl(keychain, primaryKey);
128 keychain->addItem(primaryKey, ii);
129 return ii;
130 }
131
132
133
134 // Constructor used when copying an item to a keychain.
135
136 ItemImpl::ItemImpl(ItemImpl &item) :
137 mData(item.modifiedData() ? NULL : new CssmDataContainer()),
138 mDbAttributes(new DbAttributes()),
139 mKeychain(NULL),
140 mDoNotEncrypt(false),
141 mInCache(false),
142 mMutex(Mutex::recursive)
143 {
144 mDbAttributes->recordType(item.recordType());
145 CSSM_DB_RECORD_ATTRIBUTE_INFO *schemaAttributes = NULL;
146
147 if (item.mKeychain) {
148 // get the entire source item from its keychain. This requires figuring
149 // out the schema for the item based on its record type.
150
151 for (uint32 i = 0; i < Schema::DBInfo.NumberOfRecordTypes; i++)
152 if (item.recordType() == Schema::DBInfo.RecordAttributeNames[i].DataRecordType) {
153 schemaAttributes = &Schema::DBInfo.RecordAttributeNames[i];
154 break;
155 }
156
157 if (schemaAttributes == NULL)
158 // the source item is invalid
159 MacOSError::throwMe(errSecInvalidItemRef);
160
161 for (uint32 i = 0; i < schemaAttributes->NumberOfAttributes; i++)
162 mDbAttributes->add(schemaAttributes->AttributeInfo[i]);
163
164 item.getContent(mDbAttributes.get(), mData.get());
165 }
166
167 // @@@ We don't deal with modified attributes.
168
169 if (item.modifiedData())
170 // the copied data comes from the source item
171 mData = new CssmDataContainer(item.modifiedData()->Data,
172 item.modifiedData()->Length);
173 }
174
175 ItemImpl::~ItemImpl()
176 {
177 }
178
179
180
181 Mutex*
182 ItemImpl::getMutexForObject()
183 {
184 if (mKeychain.get())
185 {
186 return mKeychain->getKeychainMutex();
187 }
188
189 return NULL;
190 }
191
192
193
194 void
195 ItemImpl::aboutToDestruct()
196 {
197 if (mKeychain && *mPrimaryKey)
198 {
199 mKeychain->removeItem(mPrimaryKey, this);
200 }
201 }
202
203
204
205 void
206 ItemImpl::didModify()
207 {
208 StLock<Mutex>_(mMutex);
209 mData = NULL;
210 mDbAttributes.reset(NULL);
211 }
212
213 const CSSM_DATA &
214 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO &info)
215 {
216 static const uint32 zeroInt = 0;
217 static const double zeroDouble = 0.0;
218 static const char timeBytes[] = "20010101000000Z";
219
220 static const CSSM_DATA defaultFourBytes = { 4, (uint8 *) &zeroInt };
221 static const CSSM_DATA defaultEightBytes = { 8, (uint8 *) &zeroDouble };
222 static const CSSM_DATA defaultTime = { 16, (uint8 *) timeBytes };
223 static const CSSM_DATA defaultZeroBytes = { 0, NULL };
224
225 switch (info.AttributeFormat)
226 {
227 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
228 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
229 return defaultFourBytes;
230
231 case CSSM_DB_ATTRIBUTE_FORMAT_REAL:
232 return defaultEightBytes;
233
234 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
235 return defaultTime;
236
237 default:
238 return defaultZeroBytes;
239 }
240 }
241
242
243
244 PrimaryKey ItemImpl::addWithCopyInfo (Keychain &keychain, bool isCopy)
245 {
246 StLock<Mutex>_(mMutex);
247 // If we already have a Keychain we can't be added.
248 if (mKeychain)
249 MacOSError::throwMe(errSecDuplicateItem);
250
251 // If we don't have any attributes we can't be added.
252 // (this might occur if attempting to add the item twice, since our attributes
253 // and data are set to NULL at the end of this function.)
254 if (!mDbAttributes.get())
255 MacOSError::throwMe(errSecDuplicateItem);
256
257 CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
258
259 // update the creation and update dates on the new item
260 if (!isCopy)
261 {
262 KeychainSchema schema = keychain->keychainSchema();
263 SInt64 date;
264 GetCurrentMacLongDateTime(date);
265 if (schema->hasAttribute(recordType, kSecCreationDateItemAttr))
266 {
267 setAttribute(schema->attributeInfoFor(recordType, kSecCreationDateItemAttr), date);
268 }
269
270 if (schema->hasAttribute(recordType, kSecModDateItemAttr))
271 {
272 setAttribute(schema->attributeInfoFor(recordType, kSecModDateItemAttr), date);
273 }
274 }
275
276 // If the label (PrintName) attribute isn't specified, set a default label.
277 if (!mDoNotEncrypt && !mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr)))
278 {
279 // if doNotEncrypt was set all of the attributes are wrapped in the data blob. Don't calculate here.
280 CssmDbAttributeData *label = NULL;
281 switch (recordType)
282 {
283 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
284 label = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr));
285 break;
286
287 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
288 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
289 label = mDbAttributes->find(Schema::attributeInfo(kSecServerItemAttr));
290 // if AppleShare server name wasn't specified, try the server address
291 if (!label) label = mDbAttributes->find(Schema::attributeInfo(kSecAddressItemAttr));
292 break;
293
294 default:
295 break;
296 }
297 // if all else fails, use the account name.
298 if (!label)
299 label = mDbAttributes->find(Schema::attributeInfo(kSecAccountItemAttr));
300
301 if (label && label->size())
302 setAttribute (Schema::attributeInfo(kSecLabelItemAttr), label->at<CssmData>(0));
303 }
304
305 // get the attributes that are part of the primary key
306 const CssmAutoDbRecordAttributeInfo &primaryKeyInfos =
307 keychain->primaryKeyInfosFor(recordType);
308
309 // make sure each primary key element has a value in the item, otherwise
310 // the database will complain. we make a set of the provided attribute infos
311 // to avoid O(N^2) behavior.
312
313 DbAttributes *attributes = mDbAttributes.get();
314 typedef set<CssmDbAttributeInfo> InfoSet;
315 InfoSet infoSet;
316
317 if (!mDoNotEncrypt)
318 {
319 // make a set of all the attributes in the key
320 for (uint32 i = 0; i < attributes->size(); i++)
321 infoSet.insert(attributes->at(i).Info);
322
323 for (uint32 i = 0; i < primaryKeyInfos.size(); i++) { // check to make sure all required attributes are in the key
324 InfoSet::const_iterator it = infoSet.find(primaryKeyInfos.at(i));
325
326 if (it == infoSet.end()) { // not in the key? add the default
327 // we need to add a default value to the item attributes
328 attributes->add(primaryKeyInfos.at(i), defaultAttributeValue(primaryKeyInfos.at(i)));
329 }
330 }
331 }
332
333 Db db(keychain->database());
334 if (mDoNotEncrypt)
335 {
336 mUniqueId = db->insertWithoutEncryption (recordType, NULL, mData.get());
337 }
338 else if (useSecureStorage(db))
339 {
340 // Add the item to the secure storage db
341 SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*db));
342 if (impl == NULL)
343 {
344 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
345 }
346
347 SSDb ssDb(impl);
348
349 TrackingAllocator allocator(Allocator::standard());
350
351 // hhs replaced with the new aclFactory class
352 AclFactory aclFactory;
353 const AccessCredentials *nullCred = aclFactory.nullCred();
354
355 SecPointer<Access> access = mAccess;
356 if (!access) {
357 // create default access controls for the new item
358 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr));
359 string printName = data ? CssmData::overlay(data->Value[0]).toString() : "keychain item";
360 access = new Access(printName);
361
362 // special case for "iTools" password - allow anyone to decrypt the item
363 if (recordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD)
364 {
365 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr));
366 if (data && data->Value[0].Length == 6 && !memcmp("iTools", data->Value[0].Data, 6))
367 {
368 typedef vector<SecPointer<ACL> > AclSet;
369 AclSet acls;
370 access->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT, acls);
371 for (AclSet::const_iterator it = acls.begin(); it != acls.end(); it++)
372 (*it)->form(ACL::allowAllForm);
373 }
374 }
375 }
376
377 // Get the handle of the DL underlying this CSPDL.
378 CSSM_DL_DB_HANDLE dldbh;
379 db->passThrough(CSSM_APPLECSPDL_DB_GET_HANDLE, NULL,
380 reinterpret_cast<void **>(&dldbh));
381
382 // Turn off autocommit on the underlying DL and remember the old state.
383 CSSM_BOOL autoCommit = CSSM_TRUE;
384 ObjectImpl::check(CSSM_DL_PassThrough(dldbh,
385 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
386 0, reinterpret_cast<void **>(&autoCommit)));
387
388 try
389 {
390 // Create a new SSGroup with temporary access controls
391 Access::Maker maker;
392 ResourceControlContext prototype;
393 maker.initialOwner(prototype, nullCred);
394 SSGroup ssGroup(ssDb, &prototype);
395
396 try
397 {
398 // Insert the record using the newly created group.
399 mUniqueId = ssDb->insert(recordType, mDbAttributes.get(),
400 mData.get(), ssGroup, maker.cred());
401 }
402 catch(...)
403 {
404 ssGroup->deleteKey(nullCred);
405 throw;
406 }
407
408 // now finalize the access controls on the group
409 access->setAccess(*ssGroup, maker);
410 mAccess = NULL; // use them and lose them
411 if (autoCommit)
412 {
413 // autoCommit was on so commit now that we are done and turn
414 // it back on.
415 ObjectImpl::check(CSSM_DL_PassThrough(dldbh,
416 CSSM_APPLEFILEDL_COMMIT, NULL, NULL));
417 CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
418 reinterpret_cast<const void *>(autoCommit), NULL);
419 }
420 }
421 catch (...)
422 {
423 if (autoCommit)
424 {
425 // autoCommit was off so rollback since we failed and turn
426 // autoCommit back on.
427 CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
428 CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
429 reinterpret_cast<const void *>(autoCommit), NULL);
430 }
431 throw;
432 }
433 }
434 else
435 {
436 // add the item to the (regular) db
437 mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
438 }
439
440 mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId);
441 mKeychain = keychain;
442
443 // Forget our data and attributes.
444 mData = NULL;
445 mDbAttributes.reset(NULL);
446
447 return mPrimaryKey;
448 }
449
450
451
452 PrimaryKey
453 ItemImpl::add (Keychain &keychain)
454 {
455 return addWithCopyInfo (keychain, false);
456 }
457
458
459
460 Item
461 ItemImpl::copyTo(const Keychain &keychain, Access *newAccess)
462 {
463 StLock<Mutex>_(mMutex);
464 Item item(*this);
465 if (newAccess)
466 item->setAccess(newAccess);
467 else
468 {
469 /* Attempt to copy the access from the current item to the newly created one. */
470 SSGroup myGroup = group();
471 if (myGroup)
472 {
473 SecPointer<Access> access = new Access(*myGroup);
474 item->setAccess(access);
475 }
476 }
477
478 keychain->addCopy(item);
479 return item;
480 }
481
482 void
483 ItemImpl::update()
484 {
485 StLock<Mutex>_(mMutex);
486 if (!mKeychain)
487 MacOSError::throwMe(errSecNoSuchKeychain);
488
489 // Don't update if nothing changed.
490 if (!isModified())
491 return;
492
493 CSSM_DB_RECORDTYPE aRecordType = recordType();
494 KeychainSchema schema = mKeychain->keychainSchema();
495
496 // Update the modification date on the item if there is a mod date attribute.
497 if (schema->hasAttribute(aRecordType, kSecModDateItemAttr))
498 {
499 SInt64 date;
500 GetCurrentMacLongDateTime(date);
501 setAttribute(schema->attributeInfoFor(aRecordType, kSecModDateItemAttr), date);
502 }
503
504 // Make sure that we have mUniqueId
505 dbUniqueRecord();
506 Db db(mUniqueId->database());
507 if (mDoNotEncrypt)
508 {
509 CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
510 memset (&attrData, 0, sizeof (attrData));
511 attrData.DataRecordType = aRecordType;
512
513 mUniqueId->modifyWithoutEncryption(aRecordType,
514 &attrData,
515 mData.get(),
516 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
517 }
518 else if (useSecureStorage(db))
519 {
520 // Add the item to the secure storage db
521 SSDbUniqueRecordImpl * impl = dynamic_cast<SSDbUniqueRecordImpl *>(&(*mUniqueId));
522 if (impl == NULL)
523 {
524 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
525 }
526
527 SSDbUniqueRecord ssUniqueId(impl);
528
529 // @@@ Share this instance
530 const AccessCredentials *autoPrompt = globals().itemCredentials();
531
532
533 // Only call this is user interaction is enabled.
534 ssUniqueId->modify(aRecordType,
535 mDbAttributes.get(),
536 mData.get(),
537 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE,
538 autoPrompt);
539 }
540 else
541 {
542 mUniqueId->modify(aRecordType,
543 mDbAttributes.get(),
544 mData.get(),
545 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
546 }
547
548 if (!mDoNotEncrypt)
549 {
550 PrimaryKey oldPK = mPrimaryKey;
551 mPrimaryKey = mKeychain->makePrimaryKey(aRecordType, mUniqueId);
552
553 // Forget our data and attributes.
554 mData = NULL;
555 mDbAttributes.reset(NULL);
556
557 // Let the Keychain update what it needs to.
558 mKeychain->didUpdate(this, oldPK, mPrimaryKey);
559 }
560 }
561
562 void
563 ItemImpl::getClass(SecKeychainAttribute &attr, UInt32 *actualLength)
564 {
565 StLock<Mutex>_(mMutex);
566 if (actualLength)
567 *actualLength = sizeof(SecItemClass);
568
569 if (attr.length < sizeof(SecItemClass))
570 MacOSError::throwMe(errSecBufferTooSmall);
571
572 SecItemClass aClass = Schema::itemClassFor(recordType());
573 memcpy(attr.data, &aClass, sizeof(SecItemClass));
574 }
575
576 void
577 ItemImpl::setAttribute(SecKeychainAttribute& attr)
578 {
579 StLock<Mutex>_(mMutex);
580 setAttribute(Schema::attributeInfo(attr.tag), CssmData(attr.data, attr.length));
581 }
582
583 CSSM_DB_RECORDTYPE
584 ItemImpl::recordType()
585 {
586 StLock<Mutex>_(mMutex);
587 if (mDbAttributes.get())
588 return mDbAttributes->recordType();
589
590 return mPrimaryKey->recordType();
591 }
592
593 const DbAttributes *
594 ItemImpl::modifiedAttributes()
595 {
596 StLock<Mutex>_(mMutex);
597 return mDbAttributes.get();
598 }
599
600 const CssmData *
601 ItemImpl::modifiedData()
602 {
603 StLock<Mutex>_(mMutex);
604 return mData.get();
605 }
606
607 void
608 ItemImpl::setData(UInt32 length,const void *data)
609 {
610 StLock<Mutex>_(mMutex);
611 mData = new CssmDataContainer(data, length);
612 }
613
614 void
615 ItemImpl::setAccess(Access *newAccess)
616 {
617 StLock<Mutex>_(mMutex);
618 mAccess = newAccess;
619 }
620
621 CssmClient::DbUniqueRecord
622 ItemImpl::dbUniqueRecord()
623 {
624 StLock<Mutex>_(mMutex);
625 if (!isPersistent()) // is there no database attached?
626 {
627 MacOSError::throwMe(errSecNotAvailable);
628 }
629
630 if (!mUniqueId)
631 {
632 DbCursor cursor(mPrimaryKey->createCursor(mKeychain));
633 if (!cursor->next(NULL, NULL, mUniqueId))
634 MacOSError::throwMe(errSecInvalidItemRef);
635 }
636
637 return mUniqueId;
638 }
639
640 PrimaryKey
641 ItemImpl::primaryKey()
642 {
643 return mPrimaryKey;
644 }
645
646 bool
647 ItemImpl::isPersistent()
648 {
649 return mKeychain;
650 }
651
652 bool
653 ItemImpl::isModified()
654 {
655 StLock<Mutex>_(mMutex);
656 return mData.get() || mDbAttributes.get();
657 }
658
659 Keychain
660 ItemImpl::keychain()
661 {
662 return mKeychain;
663 }
664
665 bool
666 ItemImpl::operator < (const ItemImpl &other)
667 {
668 if (mData && *mData)
669 {
670 // Pointer compare
671 return this < &other;
672 }
673
674 return mPrimaryKey < other.mPrimaryKey;
675 }
676
677 void
678 ItemImpl::setAttribute(const CssmDbAttributeInfo &info, const CssmPolyData &data)
679 {
680 StLock<Mutex>_(mMutex);
681 if (!mDbAttributes.get())
682 {
683 mDbAttributes.reset(new DbAttributes());
684 mDbAttributes->recordType(mPrimaryKey->recordType());
685 }
686
687 uint32 length = data.Length;
688 const void *buf = reinterpret_cast<const void *>(data.Data);
689 uint8 timeString[16];
690
691 // XXX This code is duplicated in KCCursorImpl::KCCursorImpl()
692 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
693 // style attribute value.
694 if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
695 {
696 if (length == sizeof(UInt32))
697 {
698 MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf), 16, &timeString);
699 buf = &timeString;
700 length = 16;
701 }
702 else if (length == sizeof(SInt64))
703 {
704 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf), 16, &timeString);
705 buf = &timeString;
706 length = 16;
707 }
708 }
709
710 mDbAttributes->add(info, CssmData(const_cast<void*>(buf), length));
711 }
712
713 void
714 ItemImpl::modifyContent(const SecKeychainAttributeList *attrList, UInt32 dataLength, const void *inData)
715 {
716 StLock<Mutex>_(mMutex);
717 if (!mDbAttributes.get())
718 {
719 mDbAttributes.reset(new DbAttributes());
720 mDbAttributes->recordType(mPrimaryKey->recordType());
721 }
722
723 if(attrList) // optional
724 {
725 for(UInt32 ix=0; ix < attrList->count; ix++)
726 {
727 SecKeychainAttrType attrTag = attrList->attr[ix].tag;
728
729 if (attrTag == APPLEDB_CSSM_PRINTNAME_ATTRIBUTE)
730 {
731 // must remap a caller-supplied kSecKeyPrintName attribute tag for key items, since it isn't in the schema
732 // (note that this will ultimately match kGenericPrintName in Schema.cpp)
733 attrTag = kSecLabelItemAttr;
734 }
735
736 mDbAttributes->add(Schema::attributeInfo(attrTag), CssmData(attrList->attr[ix].data, attrList->attr[ix].length));
737 }
738 }
739
740 if(inData)
741 {
742 mData = new CssmDataContainer(inData, dataLength);
743 }
744
745 update();
746 }
747
748 void
749 ItemImpl::getContent(SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData)
750 {
751 StLock<Mutex>_(mMutex);
752 // If the data hasn't been set we can't return it.
753 if (!mKeychain && outData)
754 {
755 CssmData *data = mData.get();
756 if (!data)
757 MacOSError::throwMe(errSecDataNotAvailable);
758 }
759 // TODO: need to check and make sure attrs are valid and handle error condition
760
761
762 if (itemClass)
763 *itemClass = Schema::itemClassFor(recordType());
764
765 bool getDataFromDatabase = mKeychain && mPrimaryKey;
766 if (getDataFromDatabase) // are we attached to a database?
767 {
768 dbUniqueRecord();
769
770 // get the number of attributes requested by the caller
771 UInt32 attrCount = attrList ? attrList->count : 0;
772
773 // make a DBAttributes structure and populate it
774 DbAttributes dbAttributes(mUniqueId->database(), attrCount);
775 for (UInt32 ix = 0; ix < attrCount; ++ix)
776 {
777 dbAttributes.add(Schema::attributeInfo(attrList->attr[ix].tag));
778 }
779
780 // request the data from the database (since we are a reference "item" and the data is really stored there)
781 CssmDataContainer itemData;
782 getContent(&dbAttributes, outData ? &itemData : NULL);
783
784 // retrieve the data from result
785 for (UInt32 ix = 0; ix < attrCount; ++ix)
786 {
787 if (dbAttributes.at(ix).NumberOfValues > 0)
788 {
789 attrList->attr[ix].data = dbAttributes.at(ix).Value[0].Data;
790 attrList->attr[ix].length = dbAttributes.at(ix).Value[0].Length;
791
792 // We don't want the data released, it is up the client
793 dbAttributes.at(ix).Value[0].Data = NULL;
794 dbAttributes.at(ix).Value[0].Length = 0;
795 }
796 else
797 {
798 attrList->attr[ix].data = NULL;
799 attrList->attr[ix].length = 0;
800 }
801 }
802
803 // clean up
804 if (outData)
805 {
806 *outData=itemData.data();
807 itemData.Data = NULL;
808
809 if (length)
810 *length=itemData.length();
811 itemData.Length = 0;
812 }
813 }
814 else
815 {
816 getLocalContent(attrList, length, outData);
817 }
818
819 // Inform anyone interested that we are doing this
820 #if SENDACCESSNOTIFICATIONS
821 if (outData)
822 {
823 secdebug("kcnotify", "ItemImpl::getContent(%p, %p, %p, %p) retrieved content",
824 itemClass, attrList, length, outData);
825
826 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
827 }
828 #endif
829 }
830
831 void
832 ItemImpl::freeContent(SecKeychainAttributeList *attrList, void *data)
833 {
834 Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
835 if (data)
836 allocator.free(data);
837
838 UInt32 attrCount = attrList ? attrList->count : 0;
839 for (UInt32 ix = 0; ix < attrCount; ++ix)
840 {
841 allocator.free(attrList->attr[ix].data);
842 attrList->attr[ix].data = NULL;
843 }
844 }
845
846 void
847 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList *attrList, UInt32 dataLength, const void *inData)
848 {
849 StLock<Mutex>_(mMutex);
850 if (!mKeychain)
851 MacOSError::throwMe(errSecNoSuchKeychain);
852
853 if (!mDoNotEncrypt)
854 {
855 if (!mDbAttributes.get())
856 {
857 mDbAttributes.reset(new DbAttributes());
858 mDbAttributes->recordType(mPrimaryKey->recordType());
859 }
860
861 CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
862 UInt32 attrCount = attrList ? attrList->count : 0;
863 for (UInt32 ix = 0; ix < attrCount; ix++)
864 {
865 SecKeychainAttrType attrTag = attrList->attr[ix].tag;
866
867 if (attrTag == kSecLabelItemAttr)
868 {
869 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema
870 // (note that this will ultimately match kGenericPrintName in Schema.cpp)
871 if (IS_PASSWORD_ITEM_CLASS( Schema::itemClassFor(recordType) ))
872 attrTag = APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE;
873 }
874
875 CssmDbAttributeInfo info=mKeychain->attributeInfoFor(recordType, attrTag);
876
877 if (attrList->attr[ix].length || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_STRING || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
878 || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_STRING || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
879 || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32)
880 mDbAttributes->add(info, CssmData(attrList->attr[ix].data, attrList->attr[ix].length));
881 else
882 mDbAttributes->add(info);
883 }
884 }
885
886 if(inData)
887 {
888 mData = new CssmDataContainer(inData, dataLength);
889 }
890
891 update();
892 }
893
894 void
895 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *itemClass,
896 SecKeychainAttributeList **attrList, UInt32 *length, void **outData)
897 {
898 StLock<Mutex>_(mMutex);
899 // If the data hasn't been set we can't return it.
900 if (!mKeychain && outData)
901 {
902 CssmData *data = mData.get();
903 if (!data)
904 MacOSError::throwMe(errSecDataNotAvailable);
905 }
906 // TODO: need to check and make sure attrs are valid and handle error condition
907
908 SecItemClass myItemClass = Schema::itemClassFor(recordType());
909 if (itemClass)
910 *itemClass = myItemClass;
911
912 // @@@ This call won't work for floating items (like certificates).
913 dbUniqueRecord();
914
915 UInt32 attrCount = info ? info->count : 0;
916 DbAttributes dbAttributes(mUniqueId->database(), attrCount);
917 for (UInt32 ix = 0; ix < attrCount; ix++)
918 {
919 CssmDbAttributeData &record = dbAttributes.add();
920 record.Info.AttributeNameFormat=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
921 record.Info.Label.AttributeID=info->tag[ix];
922
923 if (record.Info.Label.AttributeID == kSecLabelItemAttr)
924 {
925 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema
926 if (IS_PASSWORD_ITEM_CLASS( myItemClass ))
927 record.Info.Label.AttributeID = APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE;
928 }
929 }
930
931 CssmDataContainer itemData;
932 getContent(&dbAttributes, outData ? &itemData : NULL);
933
934 if (info && attrList)
935 {
936 SecKeychainAttributeList *theList=reinterpret_cast<SecKeychainAttributeList *>(malloc(sizeof(SecKeychainAttributeList)));
937 SecKeychainAttribute *attr=reinterpret_cast<SecKeychainAttribute *>(malloc(sizeof(SecKeychainAttribute)*attrCount));
938 theList->count=attrCount;
939 theList->attr=attr;
940
941 for (UInt32 ix = 0; ix < attrCount; ++ix)
942 {
943 attr[ix].tag=info->tag[ix];
944
945 if (dbAttributes.at(ix).NumberOfValues > 0)
946 {
947 attr[ix].data = dbAttributes.at(ix).Value[0].Data;
948 attr[ix].length = dbAttributes.at(ix).Value[0].Length;
949
950 // We don't want the data released, it is up the client
951 dbAttributes.at(ix).Value[0].Data = NULL;
952 dbAttributes.at(ix).Value[0].Length = 0;
953 }
954 else
955 {
956 attr[ix].data = NULL;
957 attr[ix].length = 0;
958 }
959 }
960 *attrList=theList;
961 }
962
963 if (outData)
964 {
965 *outData=itemData.data();
966 itemData.Data=NULL;
967
968 if (length) *length=itemData.length();
969 itemData.Length=0;
970
971 #if SENDACCESSNOTIFICATIONS
972 secdebug("kcnotify", "ItemImpl::getAttributesAndData(%p, %p, %p, %p, %p) retrieved data",
973 info, itemClass, attrList, length, outData);
974
975 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
976 #endif
977 }
978
979 }
980
981 void
982 ItemImpl::freeAttributesAndData(SecKeychainAttributeList *attrList, void *data)
983 {
984 Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
985
986 if (data)
987 allocator.free(data);
988
989 if (attrList)
990 {
991 for (UInt32 ix = 0; ix < attrList->count; ++ix)
992 {
993 allocator.free(attrList->attr[ix].data);
994 }
995 free(attrList->attr);
996 free(attrList);
997 }
998 }
999
1000 void
1001 ItemImpl::getAttribute(SecKeychainAttribute& attr, UInt32 *actualLength)
1002 {
1003 StLock<Mutex>_(mMutex);
1004 if (attr.tag == kSecClassItemAttr)
1005 return getClass(attr, actualLength);
1006
1007 if (mDbAttributes.get())
1008 {
1009 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(attr.tag));
1010 if (data)
1011 {
1012 getAttributeFrom(data, attr, actualLength);
1013 return;
1014 }
1015 }
1016
1017 if (!mKeychain)
1018 MacOSError::throwMe(errSecNoSuchAttr);
1019
1020 dbUniqueRecord();
1021 DbAttributes dbAttributes(mUniqueId->database(), 1);
1022 dbAttributes.add(Schema::attributeInfo(attr.tag));
1023 mUniqueId->get(&dbAttributes, NULL);
1024 getAttributeFrom(&dbAttributes.at(0), attr, actualLength);
1025 }
1026
1027 void
1028 ItemImpl::getAttributeFrom(CssmDbAttributeData *data, SecKeychainAttribute &attr, UInt32 *actualLength)
1029 {
1030 StLock<Mutex>_(mMutex);
1031 static const uint32 zero = 0;
1032 uint32 length;
1033 const void *buf = NULL;
1034
1035 // Temporary storage for buf.
1036 sint64 macLDT;
1037 uint32 macSeconds;
1038 sint16 svalue16;
1039 uint16 uvalue16;
1040 sint8 svalue8;
1041 uint8 uvalue8;
1042
1043 if (!data)
1044 length = 0;
1045 else if (data->size() < 1) // Attribute has no values.
1046 {
1047 if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
1048 || data->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
1049 {
1050 length = sizeof(zero);
1051 buf = &zero;
1052 }
1053 else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
1054 length = 0; // Should we throw here?
1055 else // All other formats
1056 length = 0;
1057 }
1058 else // Get the first value
1059 {
1060 length = data->Value[0].Length;
1061 buf = data->Value[0].Data;
1062
1063 if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32)
1064 {
1065 if (attr.length == sizeof(sint8))
1066 {
1067 length = attr.length;
1068 svalue8 = sint8(*reinterpret_cast<const sint32 *>(buf));
1069 buf = &svalue8;
1070 }
1071 else if (attr.length == sizeof(sint16))
1072 {
1073 length = attr.length;
1074 svalue16 = sint16(*reinterpret_cast<const sint32 *>(buf));
1075 buf = &svalue16;
1076 }
1077 }
1078 else if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
1079 {
1080 if (attr.length == sizeof(uint8))
1081 {
1082 length = attr.length;
1083 uvalue8 = uint8(*reinterpret_cast<const uint32 *>(buf));
1084 buf = &uvalue8;
1085 }
1086 else if (attr.length == sizeof(uint16))
1087 {
1088 length = attr.length;
1089 uvalue16 = uint16(*reinterpret_cast<const uint32 *>(buf));
1090 buf = &uvalue16;
1091 }
1092 }
1093 else if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
1094 {
1095 if (attr.length == sizeof(uint32))
1096 {
1097 TimeStringToMacSeconds(data->Value[0], macSeconds);
1098 buf = &macSeconds;
1099 length = attr.length;
1100 }
1101 else if (attr.length == sizeof(sint64))
1102 {
1103 TimeStringToMacLongDateTime(data->Value[0], macLDT);
1104 buf = &macLDT;
1105 length = attr.length;
1106 }
1107 }
1108 }
1109
1110 if (actualLength)
1111 *actualLength = length;
1112
1113 if (length)
1114 {
1115 if (attr.length < length)
1116 MacOSError::throwMe(errSecBufferTooSmall);
1117
1118 memcpy(attr.data, buf, length);
1119 }
1120 }
1121
1122 void
1123 ItemImpl::getData(CssmDataContainer& outData)
1124 {
1125 StLock<Mutex>_(mMutex);
1126 if (!mKeychain)
1127 {
1128 CssmData *data = mData.get();
1129 // If the data hasn't been set we can't return it.
1130 if (!data)
1131 MacOSError::throwMe(errSecDataNotAvailable);
1132
1133 outData = *data;
1134 return;
1135 }
1136
1137 getContent(NULL, &outData);
1138
1139 #if SENDACCESSNOTIFICATIONS
1140 secdebug("kcnotify", "ItemImpl::getData retrieved data");
1141
1142 //%%%<might> be done elsewhere, but here is good for now
1143 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
1144 #endif
1145 }
1146
1147 SSGroup
1148 ItemImpl::group()
1149 {
1150 StLock<Mutex>_(mMutex);
1151 SSGroup group;
1152 if (!!mUniqueId)
1153 {
1154 Db db(mKeychain->database());
1155 if (useSecureStorage(db))
1156 {
1157 group = safer_cast<SSDbUniqueRecordImpl &>(*mUniqueId).group();
1158 }
1159 }
1160
1161 return group;
1162 }
1163
1164 void ItemImpl::getLocalContent(SecKeychainAttributeList *attributeList, UInt32 *outLength, void **outData)
1165 {
1166 StLock<Mutex>_(mMutex);
1167 willRead();
1168 Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
1169 if (outData)
1170 {
1171 CssmData *data = mData.get();
1172 if (!data)
1173 MacOSError::throwMe(errSecDataNotAvailable);
1174
1175 // Copy the data out of our internal cached copy.
1176 uint32 length = data->Length;
1177 *outData = allocator.malloc(length);
1178 memcpy(*outData, data->Data, length);
1179 if (outLength)
1180 *outLength = length;
1181 }
1182
1183 if (attributeList)
1184 {
1185 if (!mDbAttributes.get())
1186 MacOSError::throwMe(errSecDataNotAvailable);
1187
1188 // Pull attributes out of a "floating" item, i.e. one that isn't attached to a database
1189 for (UInt32 ix = 0; ix < attributeList->count; ++ix)
1190 {
1191 SecKeychainAttribute &attribute = attributeList->attr[ix];
1192 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(attribute.tag));
1193 if (data && data->NumberOfValues > 0)
1194 {
1195 // Copy the data out of our internal cached copy.
1196 uint32 length = data->Value[0].Length;
1197 attribute.data = allocator.malloc(length);
1198 memcpy(attribute.data, data->Value[0].Data, length);
1199 attribute.length = length;
1200 }
1201 else
1202 {
1203 attribute.length = 0;
1204 attribute.data = NULL;
1205 }
1206 }
1207 }
1208 }
1209
1210 void
1211 ItemImpl::getContent(DbAttributes *dbAttributes, CssmDataContainer *itemData)
1212 {
1213 StLock<Mutex>_(mMutex);
1214 // Make sure mUniqueId is set.
1215 dbUniqueRecord();
1216 if (itemData)
1217 {
1218 Db db(mUniqueId->database());
1219 if (mDoNotEncrypt)
1220 {
1221 mUniqueId->getWithoutEncryption (dbAttributes, itemData);
1222 return;
1223 }
1224 if (useSecureStorage(db))
1225 {
1226 SSDbUniqueRecordImpl* impl = dynamic_cast<SSDbUniqueRecordImpl *>(&(*mUniqueId));
1227 if (impl == NULL)
1228 {
1229 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
1230 }
1231
1232 SSDbUniqueRecord ssUniqueId(impl);
1233 const AccessCredentials *autoPrompt = globals().itemCredentials();
1234 ssUniqueId->get(dbAttributes, itemData, autoPrompt);
1235 return;
1236 }
1237 }
1238
1239 mUniqueId->get(dbAttributes, itemData);
1240 }
1241
1242 bool
1243 ItemImpl::useSecureStorage(const Db &db)
1244 {
1245 StLock<Mutex>_(mMutex);
1246 switch (recordType())
1247 {
1248 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
1249 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
1250 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
1251 if (db->dl()->subserviceMask() & CSSM_SERVICE_CSP)
1252 return true;
1253 break;
1254 default:
1255 break;
1256 }
1257 return false;
1258 }
1259
1260 void ItemImpl::willRead()
1261 {
1262 }
1263
1264
1265 void ItemImpl::copyPersistentReference(CFDataRef &outDataRef)
1266 {
1267 StLock<Mutex>_(mMutex);
1268 // item must be in a keychain and have a primary key to be persistent
1269 if (!mKeychain || !mPrimaryKey) {
1270 MacOSError::throwMe(errSecItemNotFound);
1271 }
1272 DLDbIdentifier dlDbIdentifier = mKeychain->dlDbIdentifier();
1273 DLDbIdentifier newDlDbIdentifier(dlDbIdentifier.ssuid(),
1274 DLDbListCFPref::AbbreviatedPath(mKeychain->name()).c_str(),
1275 dlDbIdentifier.dbLocation());
1276 NameValueDictionary dict;
1277 NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(newDlDbIdentifier, dict);
1278
1279 CssmData* pKey = mPrimaryKey;
1280 dict.Insert (new NameValuePair(ITEM_KEY, *pKey));
1281
1282 // flatten the NameValueDictionary
1283 CssmData dictData;
1284 dict.Export(dictData);
1285 outDataRef = ::CFDataCreate(kCFAllocatorDefault, dictData.Data, dictData.Length);
1286 free (dictData.Data);
1287 }
1288
1289 void ItemImpl::copyRecordIdentifier(CSSM_DATA &data)
1290 {
1291 StLock<Mutex>_(mMutex);
1292 CssmClient::DbUniqueRecord uniqueRecord = dbUniqueRecord ();
1293 uniqueRecord->getRecordIdentifier(data);
1294 }
1295
1296 /*
1297 * Obtain blob used to bind a keychain item to an Extended Attribute record.
1298 * We just use the PrimaryKey blob as the default. Note that for standard Items,
1299 * this can cause the loss of extended attribute bindings if a Primary Key
1300 * attribute changes.
1301 */
1302 const CssmData &ItemImpl::itemID()
1303 {
1304 StLock<Mutex>_(mMutex);
1305 if(mPrimaryKey->length() == 0) {
1306 /* not in a keychain; we don't have a primary key */
1307 MacOSError::throwMe(errSecNoSuchAttr);
1308 }
1309 return *mPrimaryKey;
1310 }
1311
1312
1313 void ItemImpl::postItemEvent(SecKeychainEvent theEvent)
1314 {
1315 mKeychain->postEvent(theEvent, this);
1316 }
1317
1318
1319
1320 //
1321 // Item -- This class is here to magically create the right subclass of ItemImpl
1322 // when constructing new items.
1323 //
1324 Item::Item()
1325 {
1326 }
1327
1328 Item::Item(ItemImpl *impl) : SecPointer<ItemImpl>(impl)
1329 {
1330 }
1331
1332 Item::Item(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, bool inhibitCheck)
1333 {
1334 if (!inhibitCheck)
1335 {
1336 if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1337 || itemClass == CSSM_DL_DB_RECORD_PUBLIC_KEY
1338 || itemClass == CSSM_DL_DB_RECORD_PRIVATE_KEY
1339 || itemClass == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
1340 MacOSError::throwMe(errSecNoSuchClass); /* @@@ errSecInvalidClass */
1341 }
1342
1343 *this = new ItemImpl(itemClass, itemCreator, length, data, inhibitCheck);
1344 }
1345
1346 Item::Item(SecItemClass itemClass, SecKeychainAttributeList *attrList, UInt32 length, const void* data)
1347 {
1348 *this = new ItemImpl(itemClass, attrList, length, data);
1349 }
1350
1351 Item::Item(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
1352 : SecPointer<ItemImpl>(
1353 primaryKey->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1354 ? Certificate::make(keychain, primaryKey, uniqueId)
1355 : (primaryKey->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1356 || primaryKey->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1357 || primaryKey->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
1358 ? KeyItem::make(keychain, primaryKey, uniqueId)
1359 : primaryKey->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1360 ? ExtendedAttribute::make(keychain, primaryKey, uniqueId)
1361 : ItemImpl::make(keychain, primaryKey, uniqueId))
1362 {
1363 }
1364
1365 Item::Item(const Keychain &keychain, const PrimaryKey &primaryKey)
1366 : SecPointer<ItemImpl>(
1367 primaryKey->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1368 ? Certificate::make(keychain, primaryKey)
1369 : (primaryKey->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1370 || primaryKey->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1371 || primaryKey->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
1372 ? KeyItem::make(keychain, primaryKey)
1373 : primaryKey->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1374 ? ExtendedAttribute::make(keychain, primaryKey)
1375 : ItemImpl::make(keychain, primaryKey))
1376 {
1377 }
1378
1379 Item::Item(ItemImpl &item)
1380 : SecPointer<ItemImpl>(
1381 item.recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1382 ? new Certificate(safer_cast<Certificate &>(item))
1383 : (item.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1384 || item.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1385 || item.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
1386 ? new KeyItem(safer_cast<KeyItem &>(item))
1387 : item.recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1388 ? new ExtendedAttribute(safer_cast<ExtendedAttribute &>(item))
1389 : new ItemImpl(item))
1390 {
1391 }
1392
1393 CFIndex GetItemRetainCount(Item& item)
1394 {
1395 return CFGetRetainCount(item->handle(false));
1396 }
1397