2  * Copyright (c) 2000-2004 Apple Computer, 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 "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> 
  45 #define SENDACCESSNOTIFICATIONS 1 
  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 
  54 using namespace KeychainCore
; 
  55 using namespace CSSMDateTimeUtils
; 
  61 // NewItemImpl constructor 
  62 ItemImpl::ItemImpl(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, bool dontDoAttributes
) 
  63         : mDbAttributes(new DbAttributes()), 
  67         mMutex(Mutex::recursive
) 
  70                 mData 
= new CssmDataContainer(data
, length
); 
  72         mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
)); 
  75                 mDbAttributes
->add(Schema::attributeInfo(kSecCreatorItemAttr
), itemCreator
); 
  78 ItemImpl::ItemImpl(SecItemClass itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 length
, const void* data
) 
  79         : mDbAttributes(new DbAttributes()), 
  83         mMutex(Mutex::recursive
) 
  86                 mData 
= new CssmDataContainer(data
, length
); 
  89         mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
)); 
  93                 for(UInt32 i
=0; i 
< attrList
->count
; i
++) 
  95                         mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[i
].tag
), CssmData(attrList
->attr
[i
].data
,  attrList
->attr
[i
].length
)); 
 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
) 
 108 // PrimaryKey ItemImpl constructor 
 109 ItemImpl::ItemImpl(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
 110         : mKeychain(keychain
), mPrimaryKey(primaryKey
), mDoNotEncrypt(false), 
 112         mMutex(Mutex::recursive
) 
 116 ItemImpl
* ItemImpl::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) 
 118         ItemImpl
* ii 
= new ItemImpl(keychain
, primaryKey
, uniqueId
); 
 119         keychain
->addItem(primaryKey
, ii
); 
 125 ItemImpl
* ItemImpl::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
 127         ItemImpl
* ii 
= new ItemImpl(keychain
, primaryKey
); 
 128         keychain
->addItem(primaryKey
, ii
); 
 134 // Constructor used when copying an item to a keychain. 
 136 ItemImpl::ItemImpl(ItemImpl 
&item
) : 
 137         mData(item
.modifiedData() ? NULL 
: new CssmDataContainer()), 
 138         mDbAttributes(new DbAttributes()), 
 140         mDoNotEncrypt(false), 
 142         mMutex(Mutex::recursive
) 
 144         mDbAttributes
->recordType(item
.recordType()); 
 145         CSSM_DB_RECORD_ATTRIBUTE_INFO 
*schemaAttributes 
= NULL
; 
 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. 
 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
]; 
 157                 if (schemaAttributes 
== NULL
) 
 158                         // the source item is invalid 
 159                         MacOSError::throwMe(errSecInvalidItemRef
); 
 161                 for (uint32 i 
= 0; i 
< schemaAttributes
->NumberOfAttributes
; i
++) 
 162                         mDbAttributes
->add(schemaAttributes
->AttributeInfo
[i
]); 
 164         item
.getContent(mDbAttributes
.get(), mData
.get()); 
 167     // @@@ We don't deal with modified attributes. 
 169         if (item
.modifiedData()) 
 170                 // the copied data comes from the source item 
 171                 mData 
= new CssmDataContainer(item
.modifiedData()->Data
, 
 172                         item
.modifiedData()->Length
); 
 175 ItemImpl::~ItemImpl() 
 182 ItemImpl::getMutexForObject() 
 186                 return mKeychain
->getKeychainMutex(); 
 195 ItemImpl::aboutToDestruct() 
 197         if (mKeychain 
&& *mPrimaryKey
) 
 199                 mKeychain
->removeItem(mPrimaryKey
, this); 
 206 ItemImpl::didModify() 
 208         StLock
<Mutex
>_(mMutex
); 
 210         mDbAttributes
.reset(NULL
); 
 214 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO 
&info
) 
 216         static const uint32 zeroInt 
= 0; 
 217         static const double zeroDouble 
= 0.0; 
 218         static const char timeBytes
[] = "20010101000000Z"; 
 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 
}; 
 225         switch (info
.AttributeFormat
) 
 227                 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
: 
 228                 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
: 
 229                         return defaultFourBytes
; 
 231                 case CSSM_DB_ATTRIBUTE_FORMAT_REAL
: 
 232                         return defaultEightBytes
; 
 234                 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
: 
 238                         return defaultZeroBytes
; 
 244 PrimaryKey 
ItemImpl::addWithCopyInfo (Keychain 
&keychain
, bool isCopy
) 
 246         StLock
<Mutex
>_(mMutex
); 
 247         // If we already have a Keychain we can't be added. 
 249                 MacOSError::throwMe(errSecDuplicateItem
); 
 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
); 
 257         CSSM_DB_RECORDTYPE recordType 
= mDbAttributes
->recordType(); 
 259         // update the creation and update dates on the new item 
 262                 KeychainSchema schema 
= keychain
->keychainSchema(); 
 264                 GetCurrentMacLongDateTime(date
); 
 265                 if (schema
->hasAttribute(recordType
, kSecCreationDateItemAttr
)) 
 267                         setAttribute(schema
->attributeInfoFor(recordType
, kSecCreationDateItemAttr
), date
); 
 270                 if (schema
->hasAttribute(recordType
, kSecModDateItemAttr
)) 
 272                         setAttribute(schema
->attributeInfoFor(recordType
, kSecModDateItemAttr
), date
); 
 276     // If the label (PrintName) attribute isn't specified, set a default label. 
 277     if (!mDoNotEncrypt 
&& !mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
))) 
 279                 // if doNotEncrypt was set all of the attributes are wrapped in the data blob.  Don't calculate here. 
 280         CssmDbAttributeData 
*label 
= NULL
; 
 283             case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
: 
 284                 label 
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
)); 
 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
)); 
 297         // if all else fails, use the account name. 
 299                         label 
= mDbAttributes
->find(Schema::attributeInfo(kSecAccountItemAttr
)); 
 301         if (label 
&& label
->size()) 
 302             setAttribute (Schema::attributeInfo(kSecLabelItemAttr
), label
->at
<CssmData
>(0)); 
 305         // get the attributes that are part of the primary key 
 306         const CssmAutoDbRecordAttributeInfo 
&primaryKeyInfos 
= 
 307                 keychain
->primaryKeyInfosFor(recordType
); 
 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. 
 313         DbAttributes 
*attributes 
= mDbAttributes
.get(); 
 314         typedef set
<CssmDbAttributeInfo
> InfoSet
; 
 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
); 
 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
)); 
 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
))); 
 333         Db 
db(keychain
->database()); 
 336                 mUniqueId 
= db
->insertWithoutEncryption (recordType
, NULL
, mData
.get()); 
 338         else if (useSecureStorage(db
)) 
 340                 // Add the item to the secure storage db 
 341                 SSDbImpl
* impl 
= dynamic_cast<SSDbImpl 
*>(&(*db
)); 
 344                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 349                 TrackingAllocator 
allocator(Allocator::standard()); 
 351                 // hhs replaced with the new aclFactory class 
 352                 AclFactory aclFactory
; 
 353                 const AccessCredentials 
*nullCred 
= aclFactory
.nullCred(); 
 355                 SecPointer
<Access
> access 
= mAccess
; 
 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
); 
 362                         // special case for "iTools" password - allow anyone to decrypt the item 
 363                         if (recordType 
== CSSM_DL_DB_RECORD_GENERIC_PASSWORD
) 
 365                                 CssmDbAttributeData 
*data 
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
)); 
 366                                 if (data 
&& data
->Value
[0].Length 
== 6 && !memcmp("iTools", data
->Value
[0].Data
, 6)) 
 368                                         typedef vector
<SecPointer
<ACL
> > AclSet
; 
 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
); 
 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
)); 
 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
))); 
 390                         // Create a new SSGroup with temporary access controls 
 392                         ResourceControlContext prototype
; 
 393                         maker
.initialOwner(prototype
, nullCred
); 
 394                         SSGroup 
ssGroup(ssDb
, &prototype
); 
 398                                 // Insert the record using the newly created group. 
 399                                 mUniqueId 
= ssDb
->insert(recordType
, mDbAttributes
.get(), 
 400                                                                                  mData
.get(), ssGroup
, maker
.cred()); 
 404                                 ssGroup
->deleteKey(nullCred
); 
 408                         // now finalize the access controls on the group 
 409                         access
->setAccess(*ssGroup
, maker
); 
 410                         mAccess 
= NULL
; // use them and lose them 
 413                                 // autoCommit was on so commit now that we are done and turn 
 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
); 
 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
); 
 436                 // add the item to the (regular) db 
 437                 mUniqueId 
= db
->insert(recordType
, mDbAttributes
.get(), mData
.get()); 
 440         mPrimaryKey 
= keychain
->makePrimaryKey(recordType
, mUniqueId
); 
 441     mKeychain 
= keychain
; 
 443         // Forget our data and attributes. 
 445         mDbAttributes
.reset(NULL
); 
 453 ItemImpl::add (Keychain 
&keychain
) 
 455         return addWithCopyInfo (keychain
, false); 
 461 ItemImpl::copyTo(const Keychain 
&keychain
, Access 
*newAccess
) 
 463         StLock
<Mutex
>_(mMutex
); 
 466                 item
->setAccess(newAccess
); 
 469                 /* Attempt to copy the access from the current item to the newly created one. */ 
 470                 SSGroup myGroup 
= group(); 
 473                         SecPointer
<Access
> access 
= new Access(*myGroup
); 
 474                         item
->setAccess(access
); 
 478         keychain
->addCopy(item
); 
 485         StLock
<Mutex
>_(mMutex
); 
 487                 MacOSError::throwMe(errSecNoSuchKeychain
);  
 489         // Don't update if nothing changed. 
 493         CSSM_DB_RECORDTYPE aRecordType 
= recordType(); 
 494         KeychainSchema schema 
= mKeychain
->keychainSchema(); 
 496         // Update the modification date on the item if there is a mod date attribute. 
 497         if (schema
->hasAttribute(aRecordType
, kSecModDateItemAttr
)) 
 500                 GetCurrentMacLongDateTime(date
); 
 501                 setAttribute(schema
->attributeInfoFor(aRecordType
, kSecModDateItemAttr
), date
); 
 504         // Make sure that we have mUniqueId 
 506         Db 
db(mUniqueId
->database()); 
 509                 CSSM_DB_RECORD_ATTRIBUTE_DATA attrData
; 
 510                 memset (&attrData
, 0, sizeof (attrData
)); 
 511                 attrData
.DataRecordType 
= aRecordType
; 
 513                 mUniqueId
->modifyWithoutEncryption(aRecordType
, 
 516                                                                                    CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 518         else if (useSecureStorage(db
)) 
 520                 // Add the item to the secure storage db 
 521                 SSDbUniqueRecordImpl 
* impl 
= dynamic_cast<SSDbUniqueRecordImpl 
*>(&(*mUniqueId
)); 
 524                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 527                 SSDbUniqueRecord 
ssUniqueId(impl
); 
 529                 // @@@ Share this instance 
 530                 const AccessCredentials 
*autoPrompt 
= globals().itemCredentials(); 
 533                 // Only call this is user interaction is enabled. 
 534                 ssUniqueId
->modify(aRecordType
, 
 537                                                    CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
, 
 542                 mUniqueId
->modify(aRecordType
, 
 545                                                   CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 550                 PrimaryKey oldPK 
= mPrimaryKey
; 
 551                 mPrimaryKey 
= mKeychain
->makePrimaryKey(aRecordType
, mUniqueId
); 
 553                 // Forget our data and attributes. 
 555                 mDbAttributes
.reset(NULL
); 
 557                 // Let the Keychain update what it needs to. 
 558                 mKeychain
->didUpdate(this, oldPK
, mPrimaryKey
); 
 563 ItemImpl::getClass(SecKeychainAttribute 
&attr
, UInt32 
*actualLength
) 
 565         StLock
<Mutex
>_(mMutex
); 
 567                 *actualLength 
= sizeof(SecItemClass
); 
 569         if (attr
.length 
< sizeof(SecItemClass
)) 
 570                 MacOSError::throwMe(errSecBufferTooSmall
); 
 572         SecItemClass aClass 
= Schema::itemClassFor(recordType()); 
 573         memcpy(attr
.data
, &aClass
, sizeof(SecItemClass
)); 
 577 ItemImpl::setAttribute(SecKeychainAttribute
& attr
) 
 579         StLock
<Mutex
>_(mMutex
); 
 580     setAttribute(Schema::attributeInfo(attr
.tag
), CssmData(attr
.data
, attr
.length
)); 
 584 ItemImpl::recordType() 
 586         StLock
<Mutex
>_(mMutex
); 
 587         if (mDbAttributes
.get()) 
 588                 return mDbAttributes
->recordType(); 
 590         return mPrimaryKey
->recordType(); 
 594 ItemImpl::modifiedAttributes() 
 596         StLock
<Mutex
>_(mMutex
); 
 597         return mDbAttributes
.get(); 
 601 ItemImpl::modifiedData() 
 603         StLock
<Mutex
>_(mMutex
); 
 608 ItemImpl::setData(UInt32 length
,const void *data
) 
 610         StLock
<Mutex
>_(mMutex
); 
 611         mData 
= new CssmDataContainer(data
, length
); 
 615 ItemImpl::setAccess(Access 
*newAccess
) 
 617         StLock
<Mutex
>_(mMutex
); 
 621 CssmClient::DbUniqueRecord
 
 622 ItemImpl::dbUniqueRecord() 
 624         StLock
<Mutex
>_(mMutex
); 
 625     if (!isPersistent()) // is there no database attached? 
 627         MacOSError::throwMe(errSecNotAvailable
); 
 632                 DbCursor 
cursor(mPrimaryKey
->createCursor(mKeychain
)); 
 633                 if (!cursor
->next(NULL
, NULL
, mUniqueId
)) 
 634                         MacOSError::throwMe(errSecInvalidItemRef
); 
 641 ItemImpl::primaryKey() 
 647 ItemImpl::isPersistent() 
 653 ItemImpl::isModified() 
 655         StLock
<Mutex
>_(mMutex
); 
 656         return mData
.get() || mDbAttributes
.get(); 
 666 ItemImpl::operator < (const ItemImpl 
&other
) 
 671                 return this < &other
; 
 674         return mPrimaryKey 
< other
.mPrimaryKey
; 
 678 ItemImpl::setAttribute(const CssmDbAttributeInfo 
&info
, const CssmPolyData 
&data
) 
 680         StLock
<Mutex
>_(mMutex
); 
 681         if (!mDbAttributes
.get()) 
 683                 mDbAttributes
.reset(new DbAttributes()); 
 684                 mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
 687         uint32 length 
= data
.Length
; 
 688         const void *buf 
= reinterpret_cast<const void *>(data
.Data
); 
 689     uint8 timeString
[16]; 
 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
) 
 696         if (length 
== sizeof(UInt32
)) 
 698             MacSecondsToTimeString(*reinterpret_cast<const UInt32 
*>(buf
), 16, &timeString
); 
 702         else if (length 
== sizeof(SInt64
)) 
 704             MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 
*>(buf
), 16, &timeString
); 
 710         mDbAttributes
->add(info
, CssmData(const_cast<void*>(buf
), length
)); 
 714 ItemImpl::modifyContent(const SecKeychainAttributeList 
*attrList
, UInt32 dataLength
, const void *inData
) 
 716         StLock
<Mutex
>_(mMutex
); 
 717         if (!mDbAttributes
.get()) 
 719                 mDbAttributes
.reset(new DbAttributes()); 
 720                 mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
 723         if(attrList
) // optional 
 725                 for(UInt32 ix
=0; ix 
< attrList
->count
; ix
++) 
 727             SecKeychainAttrType attrTag 
= attrList
->attr
[ix
].tag
; 
 729             if (attrTag 
== APPLEDB_CSSM_PRINTNAME_ATTRIBUTE
) 
 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
; 
 736                         mDbAttributes
->add(Schema::attributeInfo(attrTag
), CssmData(attrList
->attr
[ix
].data
,  attrList
->attr
[ix
].length
)); 
 742                 mData 
= new CssmDataContainer(inData
, dataLength
); 
 749 ItemImpl::getContent(SecItemClass 
*itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 
*length
, void **outData
) 
 751         StLock
<Mutex
>_(mMutex
); 
 752     // If the data hasn't been set we can't return it. 
 753     if (!mKeychain 
&& outData
) 
 755                 CssmData 
*data 
= mData
.get(); 
 757                         MacOSError::throwMe(errSecDataNotAvailable
); 
 759     // TODO: need to check and make sure attrs are valid and handle error condition 
 763                 *itemClass 
= Schema::itemClassFor(recordType()); 
 765     bool getDataFromDatabase 
= mKeychain 
&& mPrimaryKey
; 
 766     if (getDataFromDatabase
) // are we attached to a database? 
 770                 // get the number of attributes requested by the caller 
 771                 UInt32 attrCount 
= attrList 
? attrList
->count 
: 0; 
 773         // make a DBAttributes structure and populate it 
 774         DbAttributes 
dbAttributes(mUniqueId
->database(), attrCount
); 
 775         for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
 777             dbAttributes
.add(Schema::attributeInfo(attrList
->attr
[ix
].tag
)); 
 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
); 
 784         // retrieve the data from result 
 785         for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
 787             if (dbAttributes
.at(ix
).NumberOfValues 
> 0) 
 789                 attrList
->attr
[ix
].data 
= dbAttributes
.at(ix
).Value
[0].Data
;     
 790                 attrList
->attr
[ix
].length 
= dbAttributes
.at(ix
).Value
[0].Length
; 
 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; 
 798                 attrList
->attr
[ix
].data 
= NULL
;  
 799                 attrList
->attr
[ix
].length 
= 0; 
 806                         *outData
=itemData
.data(); 
 807                         itemData
.Data 
= NULL
; 
 810                                 *length
=itemData
.length(); 
 816                 getLocalContent(attrList
, length
, outData
); 
 819         // Inform anyone interested that we are doing this 
 820 #if SENDACCESSNOTIFICATIONS 
 823                 secdebug("kcnotify", "ItemImpl::getContent(%p, %p, %p, %p) retrieved content", 
 824                         itemClass
, attrList
, length
, outData
); 
 826         KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this); 
 832 ItemImpl::freeContent(SecKeychainAttributeList 
*attrList
, void *data
) 
 834     Allocator 
&allocator 
= Allocator::standard(); // @@@ This might not match the one used originally 
 836                 allocator
.free(data
); 
 838     UInt32 attrCount 
= attrList 
? attrList
->count 
: 0; 
 839     for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
 841         allocator
.free(attrList
->attr
[ix
].data
); 
 842         attrList
->attr
[ix
].data 
= NULL
; 
 847 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList 
*attrList
, UInt32 dataLength
, const void *inData
) 
 849         StLock
<Mutex
>_(mMutex
); 
 851                 MacOSError::throwMe(errSecNoSuchKeychain
); 
 855                 if (!mDbAttributes
.get()) 
 857                         mDbAttributes
.reset(new DbAttributes()); 
 858                         mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
 861                 CSSM_DB_RECORDTYPE recordType 
= mDbAttributes
->recordType(); 
 862                 UInt32 attrCount 
= attrList 
? attrList
->count 
: 0; 
 863                 for (UInt32 ix 
= 0; ix 
< attrCount
; ix
++) 
 865             SecKeychainAttrType attrTag 
= attrList
->attr
[ix
].tag
; 
 867             if (attrTag 
== kSecLabelItemAttr
) 
 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
; 
 875             CssmDbAttributeInfo info
=mKeychain
->attributeInfoFor(recordType
, attrTag
); 
 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
)); 
 882                                 mDbAttributes
->add(info
); 
 888                 mData 
= new CssmDataContainer(inData
, dataLength
); 
 895 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo 
*info
, SecItemClass 
*itemClass
, 
 896                                                            SecKeychainAttributeList 
**attrList
, UInt32 
*length
, void **outData
) 
 898         StLock
<Mutex
>_(mMutex
); 
 899         // If the data hasn't been set we can't return it. 
 900         if (!mKeychain 
&& outData
) 
 902                 CssmData 
*data 
= mData
.get(); 
 904                         MacOSError::throwMe(errSecDataNotAvailable
); 
 906         // TODO: need to check and make sure attrs are valid and handle error condition 
 908     SecItemClass myItemClass 
= Schema::itemClassFor(recordType()); 
 910                 *itemClass 
= myItemClass
; 
 912         // @@@ This call won't work for floating items (like certificates). 
 915     UInt32 attrCount 
= info 
? info
->count 
: 0; 
 916         DbAttributes 
dbAttributes(mUniqueId
->database(), attrCount
); 
 917     for (UInt32 ix 
= 0; ix 
< attrCount
; ix
++) 
 919                 CssmDbAttributeData 
&record 
= dbAttributes
.add(); 
 920                 record
.Info
.AttributeNameFormat
=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
; 
 921                 record
.Info
.Label
.AttributeID
=info
->tag
[ix
]; 
 923         if (record
.Info
.Label
.AttributeID 
== kSecLabelItemAttr
) 
 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
; 
 931         CssmDataContainer itemData
; 
 932     getContent(&dbAttributes
, outData 
? &itemData 
: NULL
); 
 934         if (info 
&& attrList
) 
 936                 SecKeychainAttributeList 
*theList
=reinterpret_cast<SecKeychainAttributeList 
*>(malloc(sizeof(SecKeychainAttributeList
))); 
 937                 SecKeychainAttribute 
*attr
=reinterpret_cast<SecKeychainAttribute 
*>(malloc(sizeof(SecKeychainAttribute
)*attrCount
)); 
 938                 theList
->count
=attrCount
; 
 941                 for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
 943                         attr
[ix
].tag
=info
->tag
[ix
]; 
 945                         if (dbAttributes
.at(ix
).NumberOfValues 
> 0) 
 947                                 attr
[ix
].data 
= dbAttributes
.at(ix
).Value
[0].Data
;       
 948                                 attr
[ix
].length 
= dbAttributes
.at(ix
).Value
[0].Length
; 
 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; 
 956                                 attr
[ix
].data 
= NULL
;    
 965                 *outData
=itemData
.data(); 
 968                 if (length
) *length
=itemData
.length(); 
 971 #if SENDACCESSNOTIFICATIONS 
 972                 secdebug("kcnotify", "ItemImpl::getAttributesAndData(%p, %p, %p, %p, %p) retrieved data", 
 973                         info
, itemClass
, attrList
, length
, outData
); 
 975                 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this); 
 982 ItemImpl::freeAttributesAndData(SecKeychainAttributeList 
*attrList
, void *data
) 
 984         Allocator 
&allocator 
= Allocator::standard(); // @@@ This might not match the one used originally 
 987                 allocator
.free(data
); 
 991                 for (UInt32 ix 
= 0; ix 
< attrList
->count
; ++ix
) 
 993                         allocator
.free(attrList
->attr
[ix
].data
); 
 995                 free(attrList
->attr
); 
1001 ItemImpl::getAttribute(SecKeychainAttribute
& attr
, UInt32 
*actualLength
) 
1003         StLock
<Mutex
>_(mMutex
); 
1004         if (attr
.tag 
== kSecClassItemAttr
) 
1005                 return getClass(attr
, actualLength
); 
1007         if (mDbAttributes
.get()) 
1009                 CssmDbAttributeData 
*data 
= mDbAttributes
->find(Schema::attributeInfo(attr
.tag
)); 
1012                         getAttributeFrom(data
, attr
, actualLength
); 
1018                 MacOSError::throwMe(errSecNoSuchAttr
); 
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
); 
1028 ItemImpl::getAttributeFrom(CssmDbAttributeData 
*data
, SecKeychainAttribute 
&attr
, UInt32 
*actualLength
) 
1030         StLock
<Mutex
>_(mMutex
); 
1031     static const uint32 zero 
= 0; 
1033     const void *buf 
= NULL
; 
1035     // Temporary storage for buf. 
1045     else if (data
->size() < 1) // Attribute has no values. 
1047         if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
 
1048             || data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
) 
1050             length 
= sizeof(zero
); 
1053         else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
) 
1054             length 
= 0; // Should we throw here? 
1055         else // All other formats 
1058     else // Get the first value 
1060         length 
= data
->Value
[0].Length
; 
1061         buf 
= data
->Value
[0].Data
; 
1063         if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
) 
1065             if (attr
.length 
== sizeof(sint8
)) 
1067                 length 
= attr
.length
; 
1068                 svalue8 
= sint8(*reinterpret_cast<const sint32 
*>(buf
)); 
1071             else if (attr
.length 
== sizeof(sint16
)) 
1073                 length 
= attr
.length
; 
1074                 svalue16 
= sint16(*reinterpret_cast<const sint32 
*>(buf
)); 
1078         else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
) 
1080             if (attr
.length 
== sizeof(uint8
)) 
1082                 length 
= attr
.length
; 
1083                 uvalue8 
= uint8(*reinterpret_cast<const uint32 
*>(buf
)); 
1086             else if (attr
.length 
== sizeof(uint16
)) 
1088                 length 
= attr
.length
; 
1089                 uvalue16 
= uint16(*reinterpret_cast<const uint32 
*>(buf
)); 
1093         else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
) 
1095             if (attr
.length 
== sizeof(uint32
)) 
1097                 TimeStringToMacSeconds(data
->Value
[0], macSeconds
); 
1099                 length 
= attr
.length
; 
1101             else if (attr
.length 
== sizeof(sint64
)) 
1103                 TimeStringToMacLongDateTime(data
->Value
[0], macLDT
); 
1105                 length 
= attr
.length
; 
1111                 *actualLength 
= length
; 
1115         if (attr
.length 
< length
) 
1116                         MacOSError::throwMe(errSecBufferTooSmall
); 
1118         memcpy(attr
.data
, buf
, length
); 
1123 ItemImpl::getData(CssmDataContainer
& outData
) 
1125         StLock
<Mutex
>_(mMutex
); 
1128                 CssmData 
*data 
= mData
.get(); 
1129                 // If the data hasn't been set we can't return it. 
1131                         MacOSError::throwMe(errSecDataNotAvailable
); 
1137     getContent(NULL
, &outData
); 
1139 #if SENDACCESSNOTIFICATIONS 
1140     secdebug("kcnotify", "ItemImpl::getData retrieved data"); 
1142         //%%%<might> be done elsewhere, but here is good for now 
1143         KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this); 
1150         StLock
<Mutex
>_(mMutex
); 
1154                 Db 
db(mKeychain
->database()); 
1155                 if (useSecureStorage(db
)) 
1157                         group 
= safer_cast
<SSDbUniqueRecordImpl 
&>(*mUniqueId
).group(); 
1164 void ItemImpl::getLocalContent(SecKeychainAttributeList 
*attributeList
, UInt32 
*outLength
, void **outData
) 
1166         StLock
<Mutex
>_(mMutex
); 
1168     Allocator 
&allocator 
= Allocator::standard(); // @@@ This might not match the one used originally 
1171                 CssmData 
*data 
= mData
.get(); 
1173                         MacOSError::throwMe(errSecDataNotAvailable
); 
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
); 
1180                         *outLength 
= length
; 
1185                 if (!mDbAttributes
.get()) 
1186                         MacOSError::throwMe(errSecDataNotAvailable
); 
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
) 
1191                         SecKeychainAttribute 
&attribute 
= attributeList
->attr
[ix
]; 
1192                         CssmDbAttributeData 
*data 
= mDbAttributes
->find(Schema::attributeInfo(attribute
.tag
)); 
1193                         if (data 
&& data
->NumberOfValues 
> 0) 
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
; 
1203                                 attribute
.length 
= 0; 
1204                                 attribute
.data 
= NULL
; 
1211 ItemImpl::getContent(DbAttributes 
*dbAttributes
, CssmDataContainer 
*itemData
) 
1213         StLock
<Mutex
>_(mMutex
); 
1214     // Make sure mUniqueId is set. 
1218                 Db 
db(mUniqueId
->database()); 
1221                         mUniqueId
->getWithoutEncryption (dbAttributes
, itemData
); 
1224                 if (useSecureStorage(db
)) 
1226                         SSDbUniqueRecordImpl
* impl 
= dynamic_cast<SSDbUniqueRecordImpl 
*>(&(*mUniqueId
)); 
1229                                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
1232                         SSDbUniqueRecord 
ssUniqueId(impl
); 
1233                         const AccessCredentials 
*autoPrompt 
= globals().itemCredentials(); 
1234                         ssUniqueId
->get(dbAttributes
, itemData
, autoPrompt
); 
1239     mUniqueId
->get(dbAttributes
, itemData
);  
1243 ItemImpl::useSecureStorage(const Db 
&db
) 
1245         StLock
<Mutex
>_(mMutex
); 
1246         switch (recordType()) 
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
) 
1260 void ItemImpl::willRead() 
1265 void ItemImpl::copyPersistentReference(CFDataRef 
&outDataRef
) 
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
); 
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
); 
1279     CssmData
* pKey 
= mPrimaryKey
; 
1280     dict
.Insert (new NameValuePair(ITEM_KEY
, *pKey
)); 
1282     // flatten the NameValueDictionary 
1284     dict
.Export(dictData
); 
1285     outDataRef 
= ::CFDataCreate(kCFAllocatorDefault
, dictData
.Data
, dictData
.Length
); 
1286     free (dictData
.Data
); 
1289 void ItemImpl::copyRecordIdentifier(CSSM_DATA 
&data
) 
1291         StLock
<Mutex
>_(mMutex
); 
1292         CssmClient::DbUniqueRecord uniqueRecord 
= dbUniqueRecord (); 
1293         uniqueRecord
->getRecordIdentifier(data
); 
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.  
1302 const CssmData 
&ItemImpl::itemID() 
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
); 
1309         return *mPrimaryKey
; 
1313 void ItemImpl::postItemEvent(SecKeychainEvent theEvent
) 
1315         mKeychain
->postEvent(theEvent
, this); 
1321 // Item -- This class is here to magically create the right subclass of ItemImpl 
1322 // when constructing new items. 
1328 Item::Item(ItemImpl 
*impl
) : SecPointer
<ItemImpl
>(impl
) 
1332 Item::Item(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, bool inhibitCheck
) 
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 */ 
1343         *this = new ItemImpl(itemClass
, itemCreator
, length
, data
, inhibitCheck
); 
1346 Item::Item(SecItemClass itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 length
, const void* data
) 
1348         *this = new ItemImpl(itemClass
, attrList
, length
, data
); 
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
)) 
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
)) 
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
))  
1393 CFIndex 
GetItemRetainCount(Item
& item
) 
1395         return CFGetRetainCount(item
->handle(false));