2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
25 #include "Certificate.h"
30 #include "KCEventNotifier.h"
31 #include "cssmdatetime.h"
32 #include <Security/keychainacl.h>
33 #include <Security/osxsigning.h>
34 #include <Security/trackingallocator.h>
35 #include <Security/SecKeychainAPIPriv.h>
37 #define SENDACCESSNOTIFICATIONS 1
39 using namespace KeychainCore
;
40 using namespace CSSMDateTimeUtils
;
46 // NewItemImpl constructor
47 ItemImpl::ItemImpl(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
)
48 : mDbAttributes(new DbAttributes())
51 mData
.reset(new CssmDataContainer(data
, length
));
53 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
56 mDbAttributes
->add(Schema::attributeInfo(kSecCreatorItemAttr
), itemCreator
);
59 ItemImpl::ItemImpl(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
60 : mDbAttributes(new DbAttributes())
63 mData
.reset(new CssmDataContainer(data
, length
));
66 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
70 for(UInt32 i
=0; i
< attrList
->count
; i
++)
72 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[i
].tag
), CssmData(attrList
->attr
[i
].data
, attrList
->attr
[i
].length
));
77 // DbItemImpl constructor
78 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const DbUniqueRecord
&uniqueId
)
79 : mUniqueId(uniqueId
), mKeychain(keychain
), mPrimaryKey(primaryKey
)
81 mKeychain
->addItem(mPrimaryKey
, this);
84 // PrimaryKey ItemImpl constructor
85 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
86 : mKeychain(keychain
), mPrimaryKey(primaryKey
)
88 mKeychain
->addItem(mPrimaryKey
, this);
91 // Constructor used when copying an item to a keychain.
93 ItemImpl::ItemImpl(ItemImpl
&item
) :
94 mData(item
.modifiedData() ? NULL
: new CssmDataContainer()),
95 mDbAttributes(new DbAttributes())
97 mDbAttributes
->recordType(item
.recordType());
98 CSSM_DB_RECORD_ATTRIBUTE_INFO
*schemaAttributes
= NULL
;
100 if (item
.mKeychain
) {
101 // get the entire source item from its keychain. This requires figuring
102 // out the schema for the item based on its record type.
104 for (uint32 i
= 0; i
< Schema::DBInfo
.NumberOfRecordTypes
; i
++)
105 if (item
.recordType() == Schema::DBInfo
.RecordAttributeNames
[i
].DataRecordType
) {
106 schemaAttributes
= &Schema::DBInfo
.RecordAttributeNames
[i
];
110 if (schemaAttributes
== NULL
)
111 // the source item is invalid
112 MacOSError::throwMe(errSecInvalidItemRef
);
114 for (uint32 i
= 0; i
< schemaAttributes
->NumberOfAttributes
; i
++)
115 mDbAttributes
->add(schemaAttributes
->AttributeInfo
[i
]);
117 item
.getContent(mDbAttributes
.get(), mData
.get());
120 // @@@ We don't deal with modified attributes.
122 if (item
.modifiedData())
123 // the copied data comes from the source item
124 mData
.reset(new CssmDataContainer(item
.modifiedData()->Data
,
125 item
.modifiedData()->Length
));
128 ItemImpl::~ItemImpl() throw()
130 if (mKeychain
&& *mPrimaryKey
)
131 mKeychain
->removeItem(*mPrimaryKey
, this);
135 ItemImpl::didModify()
138 mDbAttributes
.reset(NULL
);
142 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO
&info
)
144 static const uint32 zeroInt
= 0;
145 static const double zeroDouble
= 0.0;
146 static const char timeBytes
[] = "20010101000000Z";
148 static const CSSM_DATA defaultFourBytes
= { 4, (uint8
*) &zeroInt
};
149 static const CSSM_DATA defaultEightBytes
= { 8, (uint8
*) &zeroDouble
};
150 static const CSSM_DATA defaultTime
= { 16, (uint8
*) timeBytes
};
151 static const CSSM_DATA defaultZeroBytes
= { 0, NULL
};
153 switch (info
.AttributeFormat
)
155 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
:
156 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
:
157 return defaultFourBytes
;
159 case CSSM_DB_ATTRIBUTE_FORMAT_REAL
:
160 return defaultEightBytes
;
162 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
:
166 return defaultZeroBytes
;
173 ItemImpl::add(Keychain
&keychain
)
175 // If we already have a Keychain we can't be added.
177 MacOSError::throwMe(errSecDuplicateItem
);
179 // If we don't have any attributes we can't be added.
180 // (this might occur if attempting to add the item twice, since our attributes
181 // and data are set to NULL at the end of this function.)
182 if (!mDbAttributes
.get())
183 MacOSError::throwMe(errSecDuplicateItem
);
185 CSSM_DB_RECORDTYPE recordType
= mDbAttributes
->recordType();
187 // update the creation and update dates on the new item
188 KeychainSchema schema
= keychain
->keychainSchema();
190 GetCurrentMacLongDateTime(date
);
191 if (schema
->hasAttribute(recordType
, kSecCreationDateItemAttr
))
193 setAttribute(schema
->attributeInfoFor(recordType
, kSecCreationDateItemAttr
), date
);
196 if (schema
->hasAttribute(recordType
, kSecModDateItemAttr
))
198 setAttribute(schema
->attributeInfoFor(recordType
, kSecModDateItemAttr
), date
);
201 // If the label (PrintName) attribute isn't specified, set a default label.
202 if (!mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
)))
204 CssmDbAttributeData
*label
= NULL
;
207 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
208 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
211 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
212 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
213 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServerItemAttr
));
214 // if AppleShare server name wasn't specified, try the server address
215 if (!label
) label
= mDbAttributes
->find(Schema::attributeInfo(kSecAddressItemAttr
));
221 // if all else fails, use the account name.
223 label
= mDbAttributes
->find(Schema::attributeInfo(kSecAccountItemAttr
));
225 if (label
&& label
->size())
226 setAttribute (Schema::attributeInfo(kSecLabelItemAttr
), label
->at
<CssmData
>(0));
229 // get the attributes that are part of the primary key
230 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfos
=
231 keychain
->primaryKeyInfosFor(recordType
);
233 // make sure each primary key element has a value in the item, otherwise
234 // the database will complain. we make a set of the provided attribute infos
235 // to avoid O(N^2) behavior.
237 DbAttributes
*attributes
= mDbAttributes
.get();
238 typedef set
<CssmDbAttributeInfo
> InfoSet
;
241 // make a set of all the attributes in the key
242 for (uint32 i
= 0; i
< attributes
->size(); i
++)
243 infoSet
.insert(attributes
->at(i
).Info
);
245 for (uint32 i
= 0; i
< primaryKeyInfos
.size(); i
++) { // check to make sure all required attributes are in the key
246 InfoSet::const_iterator it
= infoSet
.find(primaryKeyInfos
.at(i
));
248 if (it
== infoSet
.end()) { // not in the key? add the default
249 // we need to add a default value to the item attributes
250 attributes
->add(primaryKeyInfos
.at(i
), defaultAttributeValue(primaryKeyInfos
.at(i
)));
254 Db
db(keychain
->database());
255 if (useSecureStorage(db
))
257 // Add the item to the secure storage db
258 SSDb
ssDb(safe_cast
<SSDbImpl
*>(&(*db
)));
260 TrackingAllocator
allocator(CssmAllocator::standard());
262 // hhs replaced with the new aclFactory class
263 AclFactory aclFactory
;
264 const AccessCredentials
*nullCred
= aclFactory
.nullCred();
266 SecPointer
<Access
> access
= mAccess
;
268 // create default access controls for the new item
269 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
));
270 string printName
= data
? CssmData::overlay(data
->Value
[0]).toString() : "keychain item";
271 access
= new Access(printName
);
273 // special case for "iTools" password - allow anyone to decrypt the item
274 if (recordType
== CSSM_DL_DB_RECORD_GENERIC_PASSWORD
)
276 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
277 if (data
&& data
->Value
[0].Length
== 6 && !memcmp("iTools", data
->Value
[0].Data
, 6))
279 typedef vector
<SecPointer
<ACL
> > AclSet
;
281 access
->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT
, acls
);
282 for (AclSet::const_iterator it
= acls
.begin(); it
!= acls
.end(); it
++)
283 (*it
)->form(ACL::allowAllForm
);
288 // Create a new SSGroup with temporary access controls
290 ResourceControlContext prototype
;
291 maker
.initialOwner(prototype
, nullCred
);
292 SSGroup
ssGroup(ssDb
, &prototype
);
296 // Insert the record using the newly created group.
297 mUniqueId
= ssDb
->insert(recordType
, mDbAttributes
.get(),
298 mData
.get(), ssGroup
, maker
.cred());
302 ssGroup
->deleteKey(nullCred
);
306 // now finalize the access controls on the group
307 access
->setAccess(*ssGroup
, maker
);
308 mAccess
= NULL
; // use them and lose them
312 // add the item to the (regular) db
313 mUniqueId
= db
->insert(recordType
, mDbAttributes
.get(), mData
.get());
316 mPrimaryKey
= keychain
->makePrimaryKey(recordType
, mUniqueId
);
317 mKeychain
= keychain
;
319 // Forget our data and attributes.
321 mDbAttributes
.reset(NULL
);
327 ItemImpl::copyTo(const Keychain
&keychain
, Access
*newAccess
)
331 item
->setAccess(newAccess
);
334 /* Attempt to copy the access from the current item to the newly created one. */
335 SSGroup myGroup
= group();
338 SecPointer
<Access
> access
= new Access(*myGroup
);
339 item
->setAccess(access
);
351 MacOSError::throwMe(errSecNoSuchKeychain
);
353 // Don't update if nothing changed.
357 CSSM_DB_RECORDTYPE aRecordType
= recordType();
358 KeychainSchema schema
= mKeychain
->keychainSchema();
360 // Update the modification date on the item if there is a mod date attribute.
361 if (schema
->hasAttribute(aRecordType
, kSecModDateItemAttr
))
364 GetCurrentMacLongDateTime(date
);
365 setAttribute(schema
->attributeInfoFor(aRecordType
, kSecModDateItemAttr
), date
);
368 // Make sure that we have mUniqueId
370 Db
db(mUniqueId
->database());
371 if (useSecureStorage(db
))
373 // Add the item to the secure storage db
374 SSDbUniqueRecord
ssUniqueId(safe_cast
<SSDbUniqueRecordImpl
*>
377 // @@@ Share this instance
378 const AccessCredentials
*autoPrompt
= globals().credentials();
381 // Only call this is user interaction is enabled.
382 ssUniqueId
->modify(aRecordType
,
385 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
,
390 mUniqueId
->modify(aRecordType
,
393 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
396 PrimaryKey oldPK
= mPrimaryKey
;
397 mPrimaryKey
= mKeychain
->makePrimaryKey(aRecordType
, mUniqueId
);
399 // Forget our data and attributes.
401 mDbAttributes
.reset(NULL
);
403 // Let the Keychain update what it needs to.
404 mKeychain
->didUpdate(this, oldPK
, mPrimaryKey
);
408 ItemImpl::getClass(SecKeychainAttribute
&attr
, UInt32
*actualLength
)
411 *actualLength
= sizeof(SecItemClass
);
413 if (attr
.length
< sizeof(SecItemClass
))
414 MacOSError::throwMe(errSecBufferTooSmall
);
416 SecItemClass aClass
= Schema::itemClassFor(recordType());
417 memcpy(attr
.data
, &aClass
, sizeof(SecItemClass
));
421 ItemImpl::setAttribute(SecKeychainAttribute
& attr
)
423 setAttribute(Schema::attributeInfo(attr
.tag
), CssmData(attr
.data
, attr
.length
));
427 ItemImpl::recordType() const
429 if (mDbAttributes
.get())
430 return mDbAttributes
->recordType();
432 return mPrimaryKey
->recordType();
436 ItemImpl::modifiedAttributes() const
438 return mDbAttributes
.get();
442 ItemImpl::modifiedData() const
448 ItemImpl::setData(UInt32 length
,const void *data
)
450 mData
.reset(new CssmDataContainer(data
, length
));
454 ItemImpl::setAccess(Access
*newAccess
)
459 CssmClient::DbUniqueRecord
460 ItemImpl::dbUniqueRecord()
462 if (!isPersistant()) // is there no database attached?
464 MacOSError::throwMe(errSecNotAvailable
);
469 DbCursor
cursor(mPrimaryKey
->createCursor(mKeychain
));
470 if (!cursor
->next(NULL
, NULL
, mUniqueId
))
471 MacOSError::throwMe(errSecInvalidItemRef
);
478 ItemImpl::primaryKey() const
484 ItemImpl::isPersistant() const
490 ItemImpl::isModified() const
492 return mData
.get() || mDbAttributes
.get();
496 ItemImpl::keychain() const
502 ItemImpl::operator <(const ItemImpl
&other
) const
508 return this < &other
;
511 // XXX Deal with not having a mPrimaryKey
512 return *mPrimaryKey
< *(other
.mPrimaryKey
);
517 ItemImpl::setAttribute(const CssmDbAttributeInfo
&info
, const CssmPolyData
&data
)
519 if (!mDbAttributes
.get())
521 mDbAttributes
.reset(new DbAttributes());
522 mDbAttributes
->recordType(mPrimaryKey
->recordType());
525 uint32 length
= data
.Length
;
526 const void *buf
= reinterpret_cast<const void *>(data
.Data
);
527 uint8 timeString
[16];
529 // XXX This code is duplicated in KCCursorImpl::KCCursorImpl()
530 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
531 // style attribute value.
532 if (info
.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
534 if (length
== sizeof(UInt32
))
536 MacSecondsToTimeString(*reinterpret_cast<const UInt32
*>(buf
), 16, &timeString
);
540 else if (length
== sizeof(SInt64
))
542 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64
*>(buf
), 16, &timeString
);
548 mDbAttributes
->add(info
, CssmData(const_cast<void*>(buf
), length
));
552 ItemImpl::modifyContent(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
554 if (!mDbAttributes
.get())
556 mDbAttributes
.reset(new DbAttributes());
557 mDbAttributes
->recordType(mPrimaryKey
->recordType());
560 if(attrList
) // optional
562 for(UInt32 ix
=0; ix
< attrList
->count
; ix
++)
564 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[ix
].tag
), CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
570 mData
.reset(new CssmDataContainer(inData
, dataLength
));
577 ItemImpl::getContent(SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
580 // If the data hasn't been set we can't return it.
581 if (!mKeychain
&& outData
)
583 CssmData
*data
= mData
.get();
585 MacOSError::throwMe(errSecDataNotAvailable
);
587 // TODO: need to check and make sure attrs are valid and handle error condition
591 *itemClass
= Schema::itemClassFor(recordType());
593 bool getDataFromDatabase
= mKeychain
&& mPrimaryKey
;
595 if (getDataFromDatabase
) // are we attached to a database?
601 // get the number of attributes requested by the caller
602 UInt32 attrCount
= attrList
? attrList
->count
: 0;
604 if (getDataFromDatabase
)
606 // make a DBAttributes structure and populate it
607 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
608 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
610 dbAttributes
.add(Schema::attributeInfo(attrList
->attr
[ix
].tag
));
613 // request the data from the database (since we are a reference "item" and the data is really stored there)
614 CssmDataContainer itemData
;
615 if (getDataFromDatabase
)
617 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
620 // retrieve the data from result
621 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
623 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
625 attrList
->attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
626 attrList
->attr
[ix
].length
= dbAttributes
.at(ix
).Value
[0].Length
;
628 // We don't want the data released, it is up the client
629 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
630 dbAttributes
.at(ix
).Value
[0].Length
= 0;
634 attrList
->attr
[ix
].data
= NULL
;
635 attrList
->attr
[ix
].length
= 0;
642 *outData
=itemData
.data();
645 if (length
) *length
=itemData
.length();
649 else if (attrList
!= NULL
)
651 getLocalContent (*attrList
);
652 if (outData
) *outData
= NULL
;
653 if (length
) *length
= 0;
656 // inform anyone interested that we are doing this
657 #if SENDACCESSNOTIFICATIONS
660 secdebug("kcnotify", "ItemImpl::getContent(0x%x, 0x%x, 0x%x, 0x%x) retrieved content",
661 (unsigned int)itemClass
, (unsigned int)attrList
, (unsigned int)length
, (unsigned int)outData
);
663 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
669 ItemImpl::freeContent(SecKeychainAttributeList
*attrList
, void *data
)
671 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
673 allocator
.free(data
);
675 UInt32 attrCount
= attrList
? attrList
->count
: 0;
676 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
678 allocator
.free(attrList
->attr
[ix
].data
);
679 attrList
->attr
[ix
].data
= NULL
;
684 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
687 MacOSError::throwMe(errSecNoSuchKeychain
);
689 if (!mDbAttributes
.get())
691 mDbAttributes
.reset(new DbAttributes());
692 mDbAttributes
->recordType(mPrimaryKey
->recordType());
695 CSSM_DB_RECORDTYPE recordType
= mDbAttributes
->recordType();
696 UInt32 attrCount
= attrList
? attrList
->count
: 0;
697 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
699 CssmDbAttributeInfo info
=mKeychain
->attributeInfoFor(recordType
, attrList
->attr
[ix
].tag
);
701 if (attrList
->attr
[ix
].length
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
702 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
703 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
)
704 mDbAttributes
->add(info
, CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
706 mDbAttributes
->add(info
);
711 mData
.reset(new CssmDataContainer(inData
, dataLength
));
718 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
720 // If the data hasn't been set we can't return it.
721 if (!mKeychain
&& outData
)
723 CssmData
*data
= mData
.get();
725 MacOSError::throwMe(errSecDataNotAvailable
);
727 // TODO: need to check and make sure attrs are valid and handle error condition
731 *itemClass
= Schema::itemClassFor(recordType());
735 UInt32 attrCount
= info
? info
->count
: 0;
736 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
737 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
739 CssmDbAttributeData
&record
= dbAttributes
.add();
740 record
.Info
.AttributeNameFormat
=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
;
741 record
.Info
.Label
.AttributeID
=info
->tag
[ix
];
744 CssmDataContainer itemData
;
745 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
749 SecKeychainAttributeList
*theList
=reinterpret_cast<SecKeychainAttributeList
*>(malloc(sizeof(SecKeychainAttributeList
)));
750 SecKeychainAttribute
*attr
=reinterpret_cast<SecKeychainAttribute
*>(malloc(sizeof(SecKeychainAttribute
)*attrCount
));
751 theList
->count
=attrCount
;
754 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
756 attr
[ix
].tag
=info
->tag
[ix
];
758 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
760 attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
761 attr
[ix
].length
= dbAttributes
.at(ix
).Value
[0].Length
;
763 // We don't want the data released, it is up the client
764 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
765 dbAttributes
.at(ix
).Value
[0].Length
= 0;
769 attr
[ix
].data
= NULL
;
778 *outData
=itemData
.data();
781 if (length
) *length
=itemData
.length();
784 #if SENDACCESSNOTIFICATIONS
785 secdebug("kcnotify", "ItemImpl::getAttributesAndData(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) retrieved data",
786 (unsigned int)info
, (unsigned int)itemClass
, (unsigned int)attrList
, (unsigned int)length
, (unsigned int)outData
);
788 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
795 ItemImpl::freeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
797 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
800 allocator
.free(data
);
804 for (UInt32 ix
= 0; ix
< attrList
->count
; ++ix
)
806 allocator
.free(attrList
->attr
[ix
].data
);
808 free(attrList
->attr
);
814 ItemImpl::getAttribute(SecKeychainAttribute
& attr
, UInt32
*actualLength
)
816 if (attr
.tag
== kSecClassItemAttr
)
817 return getClass(attr
, actualLength
);
819 if (mDbAttributes
.get())
821 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(attr
.tag
));
824 getAttributeFrom(data
, attr
, actualLength
);
830 MacOSError::throwMe(errSecNoSuchAttr
);
833 DbAttributes
dbAttributes(mUniqueId
->database(), 1);
834 dbAttributes
.add(Schema::attributeInfo(attr
.tag
));
835 mUniqueId
->get(&dbAttributes
, NULL
);
836 getAttributeFrom(&dbAttributes
.at(0), attr
, actualLength
);
840 ItemImpl::getAttributeFrom(CssmDbAttributeData
*data
, SecKeychainAttribute
&attr
, UInt32
*actualLength
)
842 static const uint32 zero
= 0;
844 const void *buf
= NULL
;
846 // Temporary storage for buf.
856 else if (data
->size() < 1) // Attribute has no values.
858 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
859 || data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
861 length
= sizeof(zero
);
864 else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
865 length
= 0; // Should we throw here?
866 else // All other formats
869 else // Get the first value
871 length
= data
->Value
[0].Length
;
872 buf
= data
->Value
[0].Data
;
874 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
)
876 if (attr
.length
== sizeof(sint8
))
878 length
= attr
.length
;
879 svalue8
= sint8(*reinterpret_cast<const sint32
*>(buf
));
882 else if (attr
.length
== sizeof(sint16
))
884 length
= attr
.length
;
885 svalue16
= sint16(*reinterpret_cast<const sint32
*>(buf
));
889 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
891 if (attr
.length
== sizeof(uint8
))
893 length
= attr
.length
;
894 uvalue8
= uint8(*reinterpret_cast<const uint32
*>(buf
));
897 else if (attr
.length
== sizeof(uint16
))
899 length
= attr
.length
;
900 uvalue16
= uint16(*reinterpret_cast<const uint32
*>(buf
));
904 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
906 if (attr
.length
== sizeof(UInt32
))
908 TimeStringToMacSeconds(data
->Value
[0], macSeconds
);
910 length
= attr
.length
;
912 else if (attr
.length
== sizeof(SInt64
))
914 TimeStringToMacLongDateTime(data
->Value
[0], macLDT
);
916 length
= attr
.length
;
922 *actualLength
= length
;
926 if (attr
.length
< length
)
927 MacOSError::throwMe(errSecBufferTooSmall
);
929 memcpy(attr
.data
, buf
, length
);
934 ItemImpl::getData(CssmDataContainer
& outData
)
938 CssmData
*data
= mData
.get();
939 // If the data hasn't been set we can't return it.
941 MacOSError::throwMe(errSecDataNotAvailable
);
947 getContent(NULL
, &outData
);
949 #if SENDACCESSNOTIFICATIONS
950 secdebug("kcnotify", "ItemImpl::getData retrieved data");
952 //%%%<might> be done elsewhere, but here is good for now
953 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
963 Db
db(mKeychain
->database());
964 if (useSecureStorage(db
))
966 group
= safer_cast
<SSDbUniqueRecordImpl
&>(*mUniqueId
).group();
973 void ItemImpl::getLocalContent(SecKeychainAttributeList
&attributeList
)
975 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
977 // pull attributes out of a "floating" item, i.e. one that isn't attached to a database
979 for (i
= 0; i
< attributeList
.count
; ++i
)
981 // get the size of the attribute
983 SecKeychainAttribute attribute
;
984 attribute
.tag
= attributeList
.attr
[i
].tag
;
985 attribute
.length
= 0;
986 attribute
.data
= NULL
;
987 getAttribute (attribute
, &actualLength
);
989 // if we didn't get the actual length, mark zeros.
990 if (actualLength
== 0)
992 attributeList
.attr
[i
].length
= 0;
993 attributeList
.attr
[i
].data
= NULL
;
997 // make room in the item data
998 attributeList
.attr
[i
].length
= actualLength
;
999 attributeList
.attr
[i
].data
= allocator
.malloc(actualLength
);
1000 getAttribute(attributeList
.attr
[i
], &actualLength
);
1006 ItemImpl::getContent(DbAttributes
*dbAttributes
, CssmDataContainer
*itemData
)
1008 // Make sure mUniqueId is set.
1012 Db
db(mUniqueId
->database());
1013 if (useSecureStorage(db
))
1015 SSDbUniqueRecord
ssUniqueId(safe_cast
<SSDbUniqueRecordImpl
*>(&(*mUniqueId
)));
1016 const AccessCredentials
*autoPrompt
= globals().credentials();
1017 ssUniqueId
->get(dbAttributes
, itemData
, autoPrompt
);
1022 mUniqueId
->get(dbAttributes
, itemData
);
1026 ItemImpl::useSecureStorage(const Db
&db
)
1028 switch (recordType())
1030 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
1031 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
1032 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
1033 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
1044 // Item -- This class is here to magically create the right subclass of ItemImpl
1045 // when constructing new items.
1051 Item::Item(ItemImpl
*impl
) : SecPointer
<ItemImpl
>(impl
)
1055 Item::Item(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
)
1057 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
1058 || itemClass
== CSSM_DL_DB_RECORD_PUBLIC_KEY
1059 || itemClass
== CSSM_DL_DB_RECORD_PRIVATE_KEY
1060 || itemClass
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1061 MacOSError::throwMe(errSecNoSuchClass
); /* @@@ errSecInvalidClass */
1063 *this = new ItemImpl(itemClass
, itemCreator
, length
, data
);
1066 Item::Item(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
1068 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
1069 || itemClass
== CSSM_DL_DB_RECORD_PUBLIC_KEY
1070 || itemClass
== CSSM_DL_DB_RECORD_PRIVATE_KEY
1071 || itemClass
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1072 MacOSError::throwMe(errSecNoSuchClass
); /* @@@ errSecInvalidClass */
1074 *this = new ItemImpl(itemClass
, attrList
, length
, data
);
1077 Item::Item(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
)
1078 : SecPointer
<ItemImpl
>(
1079 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1080 ? new Certificate(keychain
, primaryKey
, uniqueId
)
1081 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1082 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1083 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1084 ? new KeyItem(keychain
, primaryKey
, uniqueId
)
1085 : new ItemImpl(keychain
, primaryKey
, uniqueId
))
1089 Item::Item(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
1090 : SecPointer
<ItemImpl
>(
1091 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1092 ? new Certificate(keychain
, primaryKey
)
1093 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1094 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1095 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1096 ? new KeyItem(keychain
, primaryKey
)
1097 : new ItemImpl(keychain
, primaryKey
))
1101 Item::Item(ItemImpl
&item
)
1102 : SecPointer
<ItemImpl
>(
1103 item
.recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1104 ? new Certificate(safer_cast
<Certificate
&>(item
))
1105 : (item
.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1106 || item
.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1107 || item
.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1108 ? new KeyItem(safer_cast
<KeyItem
&>(item
))
1109 : new ItemImpl(item
))