2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
31 #include "Certificate.h"
33 #include "ExtendedAttribute.h"
36 #include <security_cdsa_utilities/Schema.h>
37 #include "KCEventNotifier.h"
38 #include "KCExceptions.h"
39 #include "cssmdatetime.h"
40 #include <security_cdsa_client/keychainacl.h>
41 #include <security_utilities/osxcode.h>
42 #include <security_utilities/trackingallocator.h>
43 #include <Security/SecKeychainItemPriv.h>
44 #include <Security/cssmapple.h>
45 #include <CommonCrypto/CommonDigest.h>
47 #define SENDACCESSNOTIFICATIONS 1
49 //%%% schema indexes should be defined in Schema.h
50 #define _kSecAppleSharePasswordItemClass 'ashp'
51 #define APPLEDB_CSSM_PRINTNAME_ATTRIBUTE 1 /* schema index for label attribute of keys or certificates */
52 #define APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE 7 /* schema index for label attribute of password items */
53 #define IS_PASSWORD_ITEM_CLASS(X) ( (X) == kSecInternetPasswordItemClass || \
54 (X) == kSecGenericPasswordItemClass || \
55 (X) == _kSecAppleSharePasswordItemClass ) ? 1 : 0
57 using namespace KeychainCore
;
58 using namespace CSSMDateTimeUtils
;
64 // NewItemImpl constructor
65 ItemImpl::ItemImpl(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, bool dontDoAttributes
)
66 : mDbAttributes(new DbAttributes()),
68 secd_PersistentRef(NULL
),
71 mMutex(Mutex::recursive
)
74 mData
= new CssmDataContainer(data
, length
);
76 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
79 mDbAttributes
->add(Schema::attributeInfo(kSecCreatorItemAttr
), itemCreator
);
82 ItemImpl::ItemImpl(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
83 : mDbAttributes(new DbAttributes()),
85 secd_PersistentRef(NULL
),
88 mMutex(Mutex::recursive
)
91 mData
= new CssmDataContainer(data
, length
);
94 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
98 for(UInt32 i
=0; i
< attrList
->count
; i
++)
100 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[i
].tag
), CssmData(attrList
->attr
[i
].data
, attrList
->attr
[i
].length
));
105 // DbItemImpl constructor
106 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const DbUniqueRecord
&uniqueId
)
107 : mUniqueId(uniqueId
), mKeychain(keychain
), mPrimaryKey(primaryKey
),
108 secd_PersistentRef(NULL
), mDoNotEncrypt(false), mInCache(false),
109 mMutex(Mutex::recursive
)
113 // PrimaryKey ItemImpl constructor
114 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
115 : mKeychain(keychain
), mPrimaryKey(primaryKey
), secd_PersistentRef(NULL
), mDoNotEncrypt(false),
117 mMutex(Mutex::recursive
)
121 ItemImpl
* ItemImpl::make(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
)
123 ItemImpl
* ii
= new ItemImpl(keychain
, primaryKey
, uniqueId
);
124 keychain
->addItem(primaryKey
, ii
);
130 ItemImpl
* ItemImpl::make(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
132 ItemImpl
* ii
= new ItemImpl(keychain
, primaryKey
);
133 keychain
->addItem(primaryKey
, ii
);
139 // Constructor used when copying an item to a keychain.
141 ItemImpl::ItemImpl(ItemImpl
&item
) :
142 mData(item
.modifiedData() ? NULL
: new CssmDataContainer()),
143 mDbAttributes(new DbAttributes()),
145 secd_PersistentRef(NULL
),
146 mDoNotEncrypt(false),
148 mMutex(Mutex::recursive
)
150 mDbAttributes
->recordType(item
.recordType());
151 CSSM_DB_RECORD_ATTRIBUTE_INFO
*schemaAttributes
= NULL
;
153 if (item
.mKeychain
) {
154 // get the entire source item from its keychain. This requires figuring
155 // out the schema for the item based on its record type.
157 for (uint32 i
= 0; i
< Schema::DBInfo
.NumberOfRecordTypes
; i
++)
158 if (item
.recordType() == Schema::DBInfo
.RecordAttributeNames
[i
].DataRecordType
) {
159 schemaAttributes
= &Schema::DBInfo
.RecordAttributeNames
[i
];
163 if (schemaAttributes
== NULL
)
164 // the source item is invalid
165 MacOSError::throwMe(errSecInvalidItemRef
);
167 for (uint32 i
= 0; i
< schemaAttributes
->NumberOfAttributes
; i
++)
168 mDbAttributes
->add(schemaAttributes
->AttributeInfo
[i
]);
170 item
.getContent(mDbAttributes
.get(), mData
.get());
173 // @@@ We don't deal with modified attributes.
175 if (item
.modifiedData())
176 // the copied data comes from the source item
177 mData
= new CssmDataContainer(item
.modifiedData()->Data
,
178 item
.modifiedData()->Length
);
181 ItemImpl::~ItemImpl()
183 if (secd_PersistentRef
) {
184 CFRelease(secd_PersistentRef
);
191 ItemImpl::getMutexForObject()
195 return mKeychain
->getKeychainMutex();
204 ItemImpl::aboutToDestruct()
206 if (mKeychain
&& *mPrimaryKey
)
208 mKeychain
->removeItem(mPrimaryKey
, this);
215 ItemImpl::didModify()
217 StLock
<Mutex
>_(mMutex
);
219 mDbAttributes
.reset(NULL
);
223 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO
&info
)
225 static const uint32 zeroInt
= 0;
226 static const double zeroDouble
= 0.0;
227 static const char timeBytes
[] = "20010101000000Z";
229 static const CSSM_DATA defaultFourBytes
= { 4, (uint8
*) &zeroInt
};
230 static const CSSM_DATA defaultEightBytes
= { 8, (uint8
*) &zeroDouble
};
231 static const CSSM_DATA defaultTime
= { 16, (uint8
*) timeBytes
};
232 static const CSSM_DATA defaultZeroBytes
= { 0, NULL
};
234 switch (info
.AttributeFormat
)
236 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
:
237 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
:
238 return defaultFourBytes
;
240 case CSSM_DB_ATTRIBUTE_FORMAT_REAL
:
241 return defaultEightBytes
;
243 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
:
247 return defaultZeroBytes
;
253 PrimaryKey
ItemImpl::addWithCopyInfo (Keychain
&keychain
, bool isCopy
)
255 StLock
<Mutex
>_(mMutex
);
256 // If we already have a Keychain we can't be added.
258 MacOSError::throwMe(errSecDuplicateItem
);
260 // If we don't have any attributes we can't be added.
261 // (this might occur if attempting to add the item twice, since our attributes
262 // and data are set to NULL at the end of this function.)
263 if (!mDbAttributes
.get())
264 MacOSError::throwMe(errSecDuplicateItem
);
266 CSSM_DB_RECORDTYPE recordType
= mDbAttributes
->recordType();
268 // update the creation and update dates on the new item
271 KeychainSchema schema
= keychain
->keychainSchema();
273 GetCurrentMacLongDateTime(date
);
274 if (schema
->hasAttribute(recordType
, kSecCreationDateItemAttr
))
276 setAttribute(schema
->attributeInfoFor(recordType
, kSecCreationDateItemAttr
), date
);
279 if (schema
->hasAttribute(recordType
, kSecModDateItemAttr
))
281 setAttribute(schema
->attributeInfoFor(recordType
, kSecModDateItemAttr
), date
);
285 // If the label (PrintName) attribute isn't specified, set a default label.
286 if (!mDoNotEncrypt
&& !mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
)))
288 // if doNotEncrypt was set all of the attributes are wrapped in the data blob. Don't calculate here.
289 CssmDbAttributeData
*label
= NULL
;
292 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
293 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
296 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
297 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
298 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServerItemAttr
));
299 // if AppleShare server name wasn't specified, try the server address
300 if (!label
) label
= mDbAttributes
->find(Schema::attributeInfo(kSecAddressItemAttr
));
306 // if all else fails, use the account name.
308 label
= mDbAttributes
->find(Schema::attributeInfo(kSecAccountItemAttr
));
310 if (label
&& label
->size())
311 setAttribute (Schema::attributeInfo(kSecLabelItemAttr
), label
->at
<CssmData
>(0));
314 // get the attributes that are part of the primary key
315 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfos
=
316 keychain
->primaryKeyInfosFor(recordType
);
318 // make sure each primary key element has a value in the item, otherwise
319 // the database will complain. we make a set of the provided attribute infos
320 // to avoid O(N^2) behavior.
322 DbAttributes
*attributes
= mDbAttributes
.get();
323 typedef set
<CssmDbAttributeInfo
> InfoSet
;
328 // make a set of all the attributes in the key
329 for (uint32 i
= 0; i
< attributes
->size(); i
++)
330 infoSet
.insert(attributes
->at(i
).Info
);
332 for (uint32 i
= 0; i
< primaryKeyInfos
.size(); i
++) { // check to make sure all required attributes are in the key
333 InfoSet::const_iterator it
= infoSet
.find(primaryKeyInfos
.at(i
));
335 if (it
== infoSet
.end()) { // not in the key? add the default
336 // we need to add a default value to the item attributes
337 attributes
->add(primaryKeyInfos
.at(i
), defaultAttributeValue(primaryKeyInfos
.at(i
)));
342 Db
db(keychain
->database());
345 mUniqueId
= db
->insertWithoutEncryption (recordType
, NULL
, mData
.get());
347 else if (useSecureStorage(db
))
349 // Add the item to the secure storage db
350 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*db
));
353 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
358 TrackingAllocator
allocator(Allocator::standard());
360 // hhs replaced with the new aclFactory class
361 AclFactory aclFactory
;
362 const AccessCredentials
*nullCred
= aclFactory
.nullCred();
364 SecPointer
<Access
> access
= mAccess
;
366 // create default access controls for the new item
367 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
));
368 string printName
= data
? CssmData::overlay(data
->Value
[0]).toString() : "keychain item";
369 access
= new Access(printName
);
371 // special case for "iTools" password - allow anyone to decrypt the item
372 if (recordType
== CSSM_DL_DB_RECORD_GENERIC_PASSWORD
)
374 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
375 if (data
&& data
->Value
[0].Length
== 6 && !memcmp("iTools", data
->Value
[0].Data
, 6))
377 typedef vector
<SecPointer
<ACL
> > AclSet
;
379 access
->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT
, acls
);
380 for (AclSet::const_iterator it
= acls
.begin(); it
!= acls
.end(); it
++)
381 (*it
)->form(ACL::allowAllForm
);
386 // Get the handle of the DL underlying this CSPDL.
387 CSSM_DL_DB_HANDLE dldbh
;
388 db
->passThrough(CSSM_APPLECSPDL_DB_GET_HANDLE
, NULL
,
389 reinterpret_cast<void **>(&dldbh
));
391 // Turn off autocommit on the underlying DL and remember the old state.
392 CSSM_BOOL autoCommit
= CSSM_TRUE
;
393 ObjectImpl::check(CSSM_DL_PassThrough(dldbh
,
394 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
395 0, reinterpret_cast<void **>(&autoCommit
)));
399 // Create a new SSGroup with temporary access controls
401 ResourceControlContext prototype
;
402 maker
.initialOwner(prototype
, nullCred
);
403 SSGroup
ssGroup(ssDb
, &prototype
);
407 // Insert the record using the newly created group.
408 mUniqueId
= ssDb
->insert(recordType
, mDbAttributes
.get(),
409 mData
.get(), ssGroup
, maker
.cred());
413 ssGroup
->deleteKey(nullCred
);
417 // now finalize the access controls on the group
418 access
->setAccess(*ssGroup
, maker
);
419 mAccess
= NULL
; // use them and lose them
422 // autoCommit was on so commit now that we are done and turn
424 ObjectImpl::check(CSSM_DL_PassThrough(dldbh
,
425 CSSM_APPLEFILEDL_COMMIT
, NULL
, NULL
));
426 CSSM_DL_PassThrough(dldbh
, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
427 reinterpret_cast<const void *>(autoCommit
), NULL
);
434 // autoCommit was off so rollback since we failed and turn
435 // autoCommit back on.
436 CSSM_DL_PassThrough(dldbh
, CSSM_APPLEFILEDL_ROLLBACK
, NULL
, NULL
);
437 CSSM_DL_PassThrough(dldbh
, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
438 reinterpret_cast<const void *>(autoCommit
), NULL
);
445 // add the item to the (regular) db
446 mUniqueId
= db
->insert(recordType
, mDbAttributes
.get(), mData
.get());
449 mPrimaryKey
= keychain
->makePrimaryKey(recordType
, mUniqueId
);
450 mKeychain
= keychain
;
452 // Forget our data and attributes.
454 mDbAttributes
.reset(NULL
);
462 ItemImpl::add (Keychain
&keychain
)
464 return addWithCopyInfo (keychain
, false);
470 ItemImpl::copyTo(const Keychain
&keychain
, Access
*newAccess
)
472 StLock
<Mutex
>_(mMutex
);
475 item
->setAccess(newAccess
);
478 /* Attempt to copy the access from the current item to the newly created one. */
479 SSGroup myGroup
= group();
482 SecPointer
<Access
> access
= new Access(*myGroup
);
483 item
->setAccess(access
);
487 keychain
->addCopy(item
);
494 StLock
<Mutex
>_(mMutex
);
496 MacOSError::throwMe(errSecNoSuchKeychain
);
498 // Don't update if nothing changed.
502 CSSM_DB_RECORDTYPE aRecordType
= recordType();
503 KeychainSchema schema
= mKeychain
->keychainSchema();
505 // Update the modification date on the item if there is a mod date attribute.
506 if (schema
->hasAttribute(aRecordType
, kSecModDateItemAttr
))
509 GetCurrentMacLongDateTime(date
);
510 setAttribute(schema
->attributeInfoFor(aRecordType
, kSecModDateItemAttr
), date
);
513 // Make sure that we have mUniqueId
515 Db
db(mUniqueId
->database());
518 CSSM_DB_RECORD_ATTRIBUTE_DATA attrData
;
519 memset (&attrData
, 0, sizeof (attrData
));
520 attrData
.DataRecordType
= aRecordType
;
522 mUniqueId
->modifyWithoutEncryption(aRecordType
,
525 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
527 else if (useSecureStorage(db
))
529 // Add the item to the secure storage db
530 SSDbUniqueRecordImpl
* impl
= dynamic_cast<SSDbUniqueRecordImpl
*>(&(*mUniqueId
));
533 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
536 SSDbUniqueRecord
ssUniqueId(impl
);
538 // @@@ Share this instance
539 const AccessCredentials
*autoPrompt
= globals().itemCredentials();
542 // Only call this is user interaction is enabled.
543 ssUniqueId
->modify(aRecordType
,
546 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
,
551 mUniqueId
->modify(aRecordType
,
554 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
559 PrimaryKey oldPK
= mPrimaryKey
;
560 mPrimaryKey
= mKeychain
->makePrimaryKey(aRecordType
, mUniqueId
);
562 // Forget our data and attributes.
564 mDbAttributes
.reset(NULL
);
566 // Let the Keychain update what it needs to.
567 mKeychain
->didUpdate(this, oldPK
, mPrimaryKey
);
572 ItemImpl::getClass(SecKeychainAttribute
&attr
, UInt32
*actualLength
)
574 StLock
<Mutex
>_(mMutex
);
576 *actualLength
= sizeof(SecItemClass
);
578 if (attr
.length
< sizeof(SecItemClass
))
579 MacOSError::throwMe(errSecBufferTooSmall
);
581 SecItemClass aClass
= Schema::itemClassFor(recordType());
582 memcpy(attr
.data
, &aClass
, sizeof(SecItemClass
));
586 ItemImpl::setAttribute(SecKeychainAttribute
& attr
)
588 StLock
<Mutex
>_(mMutex
);
589 setAttribute(Schema::attributeInfo(attr
.tag
), CssmData(attr
.data
, attr
.length
));
593 ItemImpl::recordType()
595 StLock
<Mutex
>_(mMutex
);
596 if (mDbAttributes
.get())
597 return mDbAttributes
->recordType();
599 return mPrimaryKey
->recordType();
603 ItemImpl::modifiedAttributes()
605 StLock
<Mutex
>_(mMutex
);
606 return mDbAttributes
.get();
610 ItemImpl::modifiedData()
612 StLock
<Mutex
>_(mMutex
);
617 ItemImpl::setData(UInt32 length
,const void *data
)
619 StLock
<Mutex
>_(mMutex
);
620 mData
= new CssmDataContainer(data
, length
);
624 ItemImpl::setAccess(Access
*newAccess
)
626 StLock
<Mutex
>_(mMutex
);
630 CssmClient::DbUniqueRecord
631 ItemImpl::dbUniqueRecord()
633 StLock
<Mutex
>_(mMutex
);
634 if (!isPersistent()) // is there no database attached?
636 MacOSError::throwMe(errSecNotAvailable
);
641 DbCursor
cursor(mPrimaryKey
->createCursor(mKeychain
));
642 if (!cursor
->next(NULL
, NULL
, mUniqueId
))
643 MacOSError::throwMe(errSecInvalidItemRef
);
650 ItemImpl::primaryKey()
656 ItemImpl::isPersistent()
662 ItemImpl::isModified()
664 StLock
<Mutex
>_(mMutex
);
665 return mData
.get() || mDbAttributes
.get();
675 ItemImpl::operator < (const ItemImpl
&other
)
680 return this < &other
;
683 return mPrimaryKey
< other
.mPrimaryKey
;
687 ItemImpl::setAttribute(const CssmDbAttributeInfo
&info
, const CssmPolyData
&data
)
689 StLock
<Mutex
>_(mMutex
);
690 if (!mDbAttributes
.get())
692 mDbAttributes
.reset(new DbAttributes());
693 mDbAttributes
->recordType(mPrimaryKey
->recordType());
696 size_t length
= data
.Length
;
697 const void *buf
= reinterpret_cast<const void *>(data
.Data
);
698 uint8 timeString
[16];
700 // XXX This code is duplicated in KCCursorImpl::KCCursorImpl()
701 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
702 // style attribute value.
703 if (info
.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
705 if (length
== sizeof(UInt32
))
707 MacSecondsToTimeString(*reinterpret_cast<const UInt32
*>(buf
), 16, &timeString
);
711 else if (length
== sizeof(SInt64
))
713 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64
*>(buf
), 16, &timeString
);
719 mDbAttributes
->add(info
, CssmData(const_cast<void*>(buf
), length
));
723 ItemImpl::modifyContent(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
725 StLock
<Mutex
>_(mMutex
);
726 if (!mDbAttributes
.get())
728 mDbAttributes
.reset(new DbAttributes());
729 mDbAttributes
->recordType(mPrimaryKey
->recordType());
732 if(attrList
) // optional
734 for(UInt32 ix
=0; ix
< attrList
->count
; ix
++)
736 SecKeychainAttrType attrTag
= attrList
->attr
[ix
].tag
;
738 if (attrTag
== APPLEDB_CSSM_PRINTNAME_ATTRIBUTE
)
740 // must remap a caller-supplied kSecKeyPrintName attribute tag for key items, since it isn't in the schema
741 // (note that this will ultimately match kGenericPrintName in Schema.cpp)
742 attrTag
= kSecLabelItemAttr
;
745 mDbAttributes
->add(Schema::attributeInfo(attrTag
), CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
751 mData
= new CssmDataContainer(inData
, dataLength
);
758 ItemImpl::getContent(SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
760 StLock
<Mutex
>_(mMutex
);
761 // If the data hasn't been set we can't return it.
762 if (!mKeychain
&& outData
)
764 CssmData
*data
= mData
.get();
766 MacOSError::throwMe(errSecDataNotAvailable
);
768 // TODO: need to check and make sure attrs are valid and handle error condition
772 *itemClass
= Schema::itemClassFor(recordType());
774 bool getDataFromDatabase
= mKeychain
&& mPrimaryKey
;
775 if (getDataFromDatabase
) // are we attached to a database?
779 // get the number of attributes requested by the caller
780 UInt32 attrCount
= attrList
? attrList
->count
: 0;
782 // make a DBAttributes structure and populate it
783 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
784 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
786 dbAttributes
.add(Schema::attributeInfo(attrList
->attr
[ix
].tag
));
789 // request the data from the database (since we are a reference "item" and the data is really stored there)
790 CssmDataContainer itemData
;
791 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
793 // retrieve the data from result
794 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
796 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
798 attrList
->attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
799 attrList
->attr
[ix
].length
= (UInt32
)dbAttributes
.at(ix
).Value
[0].Length
;
801 // We don't want the data released, it is up the client
802 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
803 dbAttributes
.at(ix
).Value
[0].Length
= 0;
807 attrList
->attr
[ix
].data
= NULL
;
808 attrList
->attr
[ix
].length
= 0;
815 *outData
=itemData
.data();
816 itemData
.Data
= NULL
;
819 *length
=(UInt32
)itemData
.length();
825 getLocalContent(attrList
, length
, outData
);
828 // Inform anyone interested that we are doing this
829 #if SENDACCESSNOTIFICATIONS
832 secdebug("kcnotify", "ItemImpl::getContent(%p, %p, %p, %p) retrieved content",
833 itemClass
, attrList
, length
, outData
);
835 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
841 ItemImpl::freeContent(SecKeychainAttributeList
*attrList
, void *data
)
843 Allocator
&allocator
= Allocator::standard(); // @@@ This might not match the one used originally
845 allocator
.free(data
);
847 UInt32 attrCount
= attrList
? attrList
->count
: 0;
848 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
850 allocator
.free(attrList
->attr
[ix
].data
);
851 attrList
->attr
[ix
].data
= NULL
;
856 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
858 StLock
<Mutex
>_(mMutex
);
860 MacOSError::throwMe(errSecNoSuchKeychain
);
864 if (!mDbAttributes
.get())
866 mDbAttributes
.reset(new DbAttributes());
867 mDbAttributes
->recordType(mPrimaryKey
->recordType());
870 CSSM_DB_RECORDTYPE recordType
= mDbAttributes
->recordType();
871 UInt32 attrCount
= attrList
? attrList
->count
: 0;
872 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
874 SecKeychainAttrType attrTag
= attrList
->attr
[ix
].tag
;
876 if (attrTag
== kSecLabelItemAttr
)
878 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema
879 // (note that this will ultimately match kGenericPrintName in Schema.cpp)
880 if (IS_PASSWORD_ITEM_CLASS( Schema::itemClassFor(recordType
) ))
881 attrTag
= APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE
;
884 CssmDbAttributeInfo info
=mKeychain
->attributeInfoFor(recordType
, attrTag
);
886 if (attrList
->attr
[ix
].length
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
887 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
888 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
)
889 mDbAttributes
->add(info
, CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
891 mDbAttributes
->add(info
);
897 mData
= new CssmDataContainer(inData
, dataLength
);
904 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
,
905 SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
907 StLock
<Mutex
>_(mMutex
);
908 // If the data hasn't been set we can't return it.
909 if (!mKeychain
&& outData
)
911 CssmData
*data
= mData
.get();
913 MacOSError::throwMe(errSecDataNotAvailable
);
915 // TODO: need to check and make sure attrs are valid and handle error condition
917 SecItemClass myItemClass
= Schema::itemClassFor(recordType());
919 *itemClass
= myItemClass
;
921 // @@@ This call won't work for floating items (like certificates).
924 UInt32 attrCount
= info
? info
->count
: 0;
925 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
926 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
928 CssmDbAttributeData
&record
= dbAttributes
.add();
929 record
.Info
.AttributeNameFormat
=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
;
930 record
.Info
.Label
.AttributeID
=info
->tag
[ix
];
932 if (record
.Info
.Label
.AttributeID
== kSecLabelItemAttr
)
934 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema
935 if (IS_PASSWORD_ITEM_CLASS( myItemClass
))
936 record
.Info
.Label
.AttributeID
= APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE
;
940 CssmDataContainer itemData
;
941 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
943 if (info
&& attrList
)
945 SecKeychainAttributeList
*theList
=reinterpret_cast<SecKeychainAttributeList
*>(malloc(sizeof(SecKeychainAttributeList
)));
946 SecKeychainAttribute
*attr
=reinterpret_cast<SecKeychainAttribute
*>(malloc(sizeof(SecKeychainAttribute
)*attrCount
));
947 theList
->count
=attrCount
;
950 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
952 attr
[ix
].tag
=info
->tag
[ix
];
954 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
956 attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
957 attr
[ix
].length
= (UInt32
)dbAttributes
.at(ix
).Value
[0].Length
;
959 // We don't want the data released, it is up the client
960 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
961 dbAttributes
.at(ix
).Value
[0].Length
= 0;
965 attr
[ix
].data
= NULL
;
974 *outData
=itemData
.data();
977 if (length
) *length
=(UInt32
)itemData
.length();
980 #if SENDACCESSNOTIFICATIONS
981 secdebug("kcnotify", "ItemImpl::getAttributesAndData(%p, %p, %p, %p, %p) retrieved data",
982 info
, itemClass
, attrList
, length
, outData
);
984 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
991 ItemImpl::freeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
993 Allocator
&allocator
= Allocator::standard(); // @@@ This might not match the one used originally
996 allocator
.free(data
);
1000 for (UInt32 ix
= 0; ix
< attrList
->count
; ++ix
)
1002 allocator
.free(attrList
->attr
[ix
].data
);
1004 free(attrList
->attr
);
1010 ItemImpl::getAttribute(SecKeychainAttribute
& attr
, UInt32
*actualLength
)
1012 StLock
<Mutex
>_(mMutex
);
1013 if (attr
.tag
== kSecClassItemAttr
)
1014 return getClass(attr
, actualLength
);
1016 if (mDbAttributes
.get())
1018 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(attr
.tag
));
1021 getAttributeFrom(data
, attr
, actualLength
);
1027 MacOSError::throwMe(errSecNoSuchAttr
);
1030 DbAttributes
dbAttributes(mUniqueId
->database(), 1);
1031 dbAttributes
.add(Schema::attributeInfo(attr
.tag
));
1032 mUniqueId
->get(&dbAttributes
, NULL
);
1033 getAttributeFrom(&dbAttributes
.at(0), attr
, actualLength
);
1037 ItemImpl::getAttributeFrom(CssmDbAttributeData
*data
, SecKeychainAttribute
&attr
, UInt32
*actualLength
)
1039 StLock
<Mutex
>_(mMutex
);
1040 static const uint32 zero
= 0;
1042 const void *buf
= NULL
;
1044 // Temporary storage for buf.
1054 else if (data
->size() < 1) // Attribute has no values.
1056 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
1057 || data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
1059 length
= sizeof(zero
);
1062 else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
1063 length
= 0; // Should we throw here?
1064 else // All other formats
1067 else // Get the first value
1069 length
= (UInt32
)data
->Value
[0].Length
;
1070 buf
= data
->Value
[0].Data
;
1072 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
)
1074 if (attr
.length
== sizeof(sint8
))
1076 length
= attr
.length
;
1077 svalue8
= sint8(*reinterpret_cast<const sint32
*>(buf
));
1080 else if (attr
.length
== sizeof(sint16
))
1082 length
= attr
.length
;
1083 svalue16
= sint16(*reinterpret_cast<const sint32
*>(buf
));
1087 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
1089 if (attr
.length
== sizeof(uint8
))
1091 length
= attr
.length
;
1092 uvalue8
= uint8(*reinterpret_cast<const uint32
*>(buf
));
1095 else if (attr
.length
== sizeof(uint16
))
1097 length
= attr
.length
;
1098 uvalue16
= uint16(*reinterpret_cast<const uint32
*>(buf
));
1102 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
1104 if (attr
.length
== sizeof(uint32
))
1106 TimeStringToMacSeconds(data
->Value
[0], macSeconds
);
1108 length
= attr
.length
;
1110 else if (attr
.length
== sizeof(sint64
))
1112 TimeStringToMacLongDateTime(data
->Value
[0], macLDT
);
1114 length
= attr
.length
;
1120 *actualLength
= length
;
1124 if (attr
.length
< length
)
1125 MacOSError::throwMe(errSecBufferTooSmall
);
1127 memcpy(attr
.data
, buf
, length
);
1132 ItemImpl::getData(CssmDataContainer
& outData
)
1134 StLock
<Mutex
>_(mMutex
);
1137 CssmData
*data
= mData
.get();
1138 // If the data hasn't been set we can't return it.
1140 MacOSError::throwMe(errSecDataNotAvailable
);
1146 getContent(NULL
, &outData
);
1148 #if SENDACCESSNOTIFICATIONS
1149 secdebug("kcnotify", "ItemImpl::getData retrieved data");
1151 //%%%<might> be done elsewhere, but here is good for now
1152 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
1159 StLock
<Mutex
>_(mMutex
);
1163 Db
db(mKeychain
->database());
1164 if (useSecureStorage(db
))
1166 group
= safer_cast
<SSDbUniqueRecordImpl
&>(*mUniqueId
).group();
1173 void ItemImpl::getLocalContent(SecKeychainAttributeList
*attributeList
, UInt32
*outLength
, void **outData
)
1175 StLock
<Mutex
>_(mMutex
);
1177 Allocator
&allocator
= Allocator::standard(); // @@@ This might not match the one used originally
1180 CssmData
*data
= mData
.get();
1182 MacOSError::throwMe(errSecDataNotAvailable
);
1184 // Copy the data out of our internal cached copy.
1185 UInt32 length
= (UInt32
)data
->Length
;
1186 *outData
= allocator
.malloc(length
);
1187 memcpy(*outData
, data
->Data
, length
);
1189 *outLength
= length
;
1194 if (!mDbAttributes
.get())
1195 MacOSError::throwMe(errSecDataNotAvailable
);
1197 // Pull attributes out of a "floating" item, i.e. one that isn't attached to a database
1198 for (UInt32 ix
= 0; ix
< attributeList
->count
; ++ix
)
1200 SecKeychainAttribute
&attribute
= attributeList
->attr
[ix
];
1201 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(attribute
.tag
));
1202 if (data
&& data
->NumberOfValues
> 0)
1204 // Copy the data out of our internal cached copy.
1205 UInt32 length
= (UInt32
)data
->Value
[0].Length
;
1206 attribute
.data
= allocator
.malloc(length
);
1207 memcpy(attribute
.data
, data
->Value
[0].Data
, length
);
1208 attribute
.length
= length
;
1212 attribute
.length
= 0;
1213 attribute
.data
= NULL
;
1220 ItemImpl::getContent(DbAttributes
*dbAttributes
, CssmDataContainer
*itemData
)
1222 StLock
<Mutex
>_(mMutex
);
1223 // Make sure mUniqueId is set.
1227 Db
db(mUniqueId
->database());
1230 mUniqueId
->getWithoutEncryption (dbAttributes
, itemData
);
1233 if (useSecureStorage(db
))
1235 SSDbUniqueRecordImpl
* impl
= dynamic_cast<SSDbUniqueRecordImpl
*>(&(*mUniqueId
));
1238 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
1241 SSDbUniqueRecord
ssUniqueId(impl
);
1242 const AccessCredentials
*autoPrompt
= globals().itemCredentials();
1243 ssUniqueId
->get(dbAttributes
, itemData
, autoPrompt
);
1248 mUniqueId
->get(dbAttributes
, itemData
);
1252 ItemImpl::useSecureStorage(const Db
&db
)
1254 StLock
<Mutex
>_(mMutex
);
1255 switch (recordType())
1257 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
1258 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
1259 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
1260 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
1269 void ItemImpl::willRead()
1273 Item
ItemImpl::makeFromPersistentReference(const CFDataRef persistentRef
, bool *isIdentityRef
)
1275 CssmData
dictData((void*)::CFDataGetBytePtr(persistentRef
), ::CFDataGetLength(persistentRef
));
1276 NameValueDictionary
dict(dictData
);
1279 Item item
= (ItemImpl
*) NULL
;
1281 if (isIdentityRef
) {
1282 *isIdentityRef
= (dict
.FindByName(IDENTITY_KEY
) != 0) ? true : false;
1285 // make sure we have a database identifier
1286 if (dict
.FindByName(SSUID_KEY
) != 0)
1288 DLDbIdentifier dlDbIdentifier
= NameValueDictionary::MakeDLDbIdentifierFromNameValueDictionary(dict
);
1289 DLDbIdentifier
newDlDbIdentifier(dlDbIdentifier
.ssuid(),
1290 DLDbListCFPref::ExpandTildesInPath(dlDbIdentifier
.dbName()).c_str(),
1291 dlDbIdentifier
.dbLocation());
1293 keychain
= globals().storageManager
.keychain(newDlDbIdentifier
);
1295 const NameValuePair
* aDictItem
= dict
.FindByName(ITEM_KEY
);
1296 if (aDictItem
&& keychain
)
1298 PrimaryKey
primaryKey(aDictItem
->Value());
1299 item
= keychain
->item(primaryKey
);
1302 KCThrowIf_( !item
, errSecItemNotFound
);
1306 void ItemImpl::copyPersistentReference(CFDataRef
&outDataRef
, bool isSecIdentityRef
)
1308 if (secd_PersistentRef
) {
1309 outDataRef
= secd_PersistentRef
;
1312 StLock
<Mutex
>_(mMutex
);
1313 // item must be in a keychain and have a primary key to be persistent
1314 if (!mKeychain
|| !mPrimaryKey
) {
1315 MacOSError::throwMe(errSecItemNotFound
);
1317 DLDbIdentifier dlDbIdentifier
= mKeychain
->dlDbIdentifier();
1318 DLDbIdentifier
newDlDbIdentifier(dlDbIdentifier
.ssuid(),
1319 DLDbListCFPref::AbbreviatedPath(mKeychain
->name()).c_str(),
1320 dlDbIdentifier
.dbLocation());
1321 NameValueDictionary dict
;
1322 NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(newDlDbIdentifier
, dict
);
1324 CssmData
* pKey
= mPrimaryKey
;
1325 dict
.Insert (new NameValuePair(ITEM_KEY
, *pKey
));
1327 if (isSecIdentityRef
) {
1328 uint32_t value
= -1;
1329 CssmData
valueData((void*)&value
, sizeof(value
));
1330 dict
.Insert (new NameValuePair(IDENTITY_KEY
, valueData
));
1333 // flatten the NameValueDictionary
1335 dict
.Export(dictData
);
1336 outDataRef
= ::CFDataCreate(kCFAllocatorDefault
, dictData
.Data
, dictData
.Length
);
1337 free (dictData
.Data
);
1340 void ItemImpl::copyRecordIdentifier(CSSM_DATA
&data
)
1342 StLock
<Mutex
>_(mMutex
);
1343 CssmClient::DbUniqueRecord uniqueRecord
= dbUniqueRecord ();
1344 uniqueRecord
->getRecordIdentifier(data
);
1348 * Obtain blob used to bind a keychain item to an Extended Attribute record.
1349 * We just use the PrimaryKey blob as the default. Note that for standard Items,
1350 * this can cause the loss of extended attribute bindings if a Primary Key
1351 * attribute changes.
1353 const CssmData
&ItemImpl::itemID()
1355 StLock
<Mutex
>_(mMutex
);
1356 if(mPrimaryKey
->length() == 0) {
1357 /* not in a keychain; we don't have a primary key */
1358 MacOSError::throwMe(errSecNoSuchAttr
);
1360 return *mPrimaryKey
;
1363 bool ItemImpl::equal(SecCFObject
&other
)
1365 // First check to see if both items have a primary key and
1366 // if the primary key is the same. If so then these
1367 // items must be equal
1368 ItemImpl
& other_item
= (ItemImpl
&)other
;
1369 if (mPrimaryKey
!= NULL
&& mPrimaryKey
== other_item
.mPrimaryKey
)
1374 // The primary keys do not match so do a CFHash of the
1375 // data of the item and compare those for equality
1376 CFHashCode this_hash
= hash();
1377 CFHashCode other_hash
= other
.hash();
1378 return (this_hash
== other_hash
);
1381 CFHashCode
ItemImpl::hash()
1383 CFHashCode result
= SecCFObject::hash();
1385 StLock
<Mutex
>_(mMutex
);
1386 RefPointer
<CssmDataContainer
> data_to_hash
;
1388 // Use the item data for the hash
1389 if (mData
&& *mData
)
1391 data_to_hash
= mData
;
1394 // If there is no primary key AND not data ????
1395 // just return the 'old' hash value which is the
1397 if (NULL
!= data_to_hash
.get())
1399 CFDataRef temp_data
= NULL
;
1400 unsigned char digest
[CC_SHA256_DIGEST_LENGTH
];
1402 if (data_to_hash
->length() < 80)
1404 // If it is less than 80 bytes then CFData can be used
1405 temp_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
1406 (const UInt8
*)data_to_hash
->data(), data_to_hash
->length(), kCFAllocatorNull
);
1409 // CFData truncates its hash value to 80 bytes. ????
1410 // In order to do the 'right thing' a SHA 256 hash will be used to
1411 // include all of the data
1414 memset(digest
, 0, CC_SHA256_DIGEST_LENGTH
);
1416 CC_SHA256((const void *)data_to_hash
->data(), (CC_LONG
)data_to_hash
->length(), digest
);
1418 temp_data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
1419 (const UInt8
*)digest
, CC_SHA256_DIGEST_LENGTH
, kCFAllocatorNull
);
1422 if (NULL
!= temp_data
)
1424 result
= CFHash(temp_data
);
1425 CFRelease(temp_data
);
1434 void ItemImpl::postItemEvent(SecKeychainEvent theEvent
)
1436 mKeychain
->postEvent(theEvent
, this);
1442 // Item -- This class is here to magically create the right subclass of ItemImpl
1443 // when constructing new items.
1449 Item::Item(ItemImpl
*impl
) : SecPointer
<ItemImpl
>(impl
)
1453 Item::Item(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, bool inhibitCheck
)
1457 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
1458 || itemClass
== CSSM_DL_DB_RECORD_PUBLIC_KEY
1459 || itemClass
== CSSM_DL_DB_RECORD_PRIVATE_KEY
1460 || itemClass
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1461 MacOSError::throwMe(errSecNoSuchClass
); /* @@@ errSecInvalidClass */
1464 *this = new ItemImpl(itemClass
, itemCreator
, length
, data
, inhibitCheck
);
1467 Item::Item(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
1469 *this = new ItemImpl(itemClass
, attrList
, length
, data
);
1472 Item::Item(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
)
1473 : SecPointer
<ItemImpl
>(
1474 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1475 ? Certificate::make(keychain
, primaryKey
, uniqueId
)
1476 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1477 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1478 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1479 ? KeyItem::make(keychain
, primaryKey
, uniqueId
)
1480 : primaryKey
->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1481 ? ExtendedAttribute::make(keychain
, primaryKey
, uniqueId
)
1482 : ItemImpl::make(keychain
, primaryKey
, uniqueId
))
1486 Item::Item(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
1487 : SecPointer
<ItemImpl
>(
1488 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1489 ? Certificate::make(keychain
, primaryKey
)
1490 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1491 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1492 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1493 ? KeyItem::make(keychain
, primaryKey
)
1494 : primaryKey
->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1495 ? ExtendedAttribute::make(keychain
, primaryKey
)
1496 : ItemImpl::make(keychain
, primaryKey
))
1500 Item::Item(ItemImpl
&item
)
1501 : SecPointer
<ItemImpl
>(
1502 item
.recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1503 ? new Certificate(safer_cast
<Certificate
&>(item
))
1504 : (item
.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1505 || item
.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1506 || item
.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1507 ? new KeyItem(safer_cast
<KeyItem
&>(item
))
1508 : item
.recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1509 ? new ExtendedAttribute(safer_cast
<ExtendedAttribute
&>(item
))
1510 : new ItemImpl(item
))
1514 CFIndex
KeychainCore::GetItemRetainCount(Item
& item
)
1516 return CFGetRetainCount(item
->handle(false));
1519 void ItemImpl::setPersistentRef(CFDataRef ref
)
1521 if (secd_PersistentRef
) {
1522 CFRelease(secd_PersistentRef
);
1524 secd_PersistentRef
= ref
;
1528 CFDataRef
ItemImpl::getPersistentRef()
1530 return secd_PersistentRef
;
1535 bool ItemImpl::mayDelete()
1537 ObjectImpl
* uniqueIDImpl
= mUniqueId
.get();
1539 if (uniqueIDImpl
!= NULL
)
1541 bool result
= mUniqueId
->isIdle();