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/aclsupport.h>
34 #include <Security/osxsigning.h>
35 #include <Security/trackingallocator.h>
36 #include <Security/SecKeychainAPIPriv.h>
38 using namespace KeychainCore
;
39 using namespace CSSMDateTimeUtils
;
45 // NewItemImpl constructor
46 ItemImpl::ItemImpl(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
)
47 : mDbAttributes(new DbAttributes())
50 mData
.reset(new CssmDataContainer(data
, length
));
52 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
55 mDbAttributes
->add(Schema::attributeInfo(kSecCreatorItemAttr
), itemCreator
);
58 ItemImpl::ItemImpl(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
59 : mDbAttributes(new DbAttributes())
62 mData
.reset(new CssmDataContainer(data
, length
));
65 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
69 for(UInt32 i
=0; i
< attrList
->count
; i
++)
71 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[i
].tag
), CssmData(attrList
->attr
[i
].data
, attrList
->attr
[i
].length
));
76 // DbItemImpl constructor
77 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const DbUniqueRecord
&uniqueId
)
78 : mUniqueId(uniqueId
), mKeychain(keychain
), mPrimaryKey(primaryKey
)
80 mKeychain
->addItem(mPrimaryKey
, this);
83 // PrimaryKey ItemImpl constructor
84 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
85 : mKeychain(keychain
), mPrimaryKey(primaryKey
)
87 mKeychain
->addItem(mPrimaryKey
, this);
90 // Constructor used when copying an item to a keychain.
92 ItemImpl::ItemImpl(ItemImpl
&item
) :
93 mData(item
.modifiedData() ? NULL
: new CssmDataContainer()),
94 mDbAttributes(new DbAttributes())
96 mDbAttributes
->recordType(item
.recordType());
97 CSSM_DB_RECORD_ATTRIBUTE_INFO
*schemaAttributes
= NULL
;
100 // get the entire source item from its keychain. This requires figuring
101 // out the schema for the item based on its record type.
103 for (uint32 i
= 0; i
< Schema::DBInfo
.NumberOfRecordTypes
; i
++)
104 if (item
.recordType() == Schema::DBInfo
.RecordAttributeNames
[i
].DataRecordType
) {
105 schemaAttributes
= &Schema::DBInfo
.RecordAttributeNames
[i
];
109 if (schemaAttributes
== NULL
)
110 // the source item is invalid
111 MacOSError::throwMe(errSecInvalidItemRef
);
113 for (uint32 i
= 0; i
< schemaAttributes
->NumberOfAttributes
; i
++)
114 mDbAttributes
->add(schemaAttributes
->AttributeInfo
[i
]);
116 item
.getContent(mDbAttributes
.get(), mData
.get());
119 // @@@ We don't deal with modified attributes.
121 if (item
.modifiedData())
122 // the copied data comes from the source item
123 mData
.reset(new CssmDataContainer(item
.modifiedData()->Data
,
124 item
.modifiedData()->Length
));
127 ItemImpl::~ItemImpl()
129 if (mKeychain
&& *mPrimaryKey
)
130 mKeychain
->removeItem(*mPrimaryKey
, this);
134 ItemImpl::didModify()
137 mDbAttributes
.reset(NULL
);
141 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO
&info
)
143 static const uint32 zeroInt
= 0;
144 static const double zeroDouble
= 0.0;
145 static const char timeBytes
[] = "20010101000000Z";
147 static const CSSM_DATA defaultFourBytes
= { 4, (uint8
*) &zeroInt
};
148 static const CSSM_DATA defaultEightBytes
= { 8, (uint8
*) &zeroDouble
};
149 static const CSSM_DATA defaultTime
= { 16, (uint8
*) timeBytes
};
150 static const CSSM_DATA defaultZeroBytes
= { 0, NULL
};
152 switch (info
.AttributeFormat
)
154 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
:
155 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
:
156 return defaultFourBytes
;
158 case CSSM_DB_ATTRIBUTE_FORMAT_REAL
:
159 return defaultEightBytes
;
161 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
:
165 return defaultZeroBytes
;
172 ItemImpl::add(Keychain
&keychain
)
174 // If we already have a Keychain we can't be added.
176 MacOSError::throwMe(errSecDuplicateItem
);
178 // If we don't have any attributes we can't be added.
179 // (this might occur if attempting to add the item twice, since our attributes
180 // and data are set to NULL at the end of this function.)
181 if (!mDbAttributes
.get())
182 MacOSError::throwMe(errSecDuplicateItem
);
184 CSSM_DB_RECORDTYPE recordType
= mDbAttributes
->recordType();
186 // update the creation and update dates on the new item
187 KeychainSchema schema
= keychain
->keychainSchema();
189 GetCurrentMacLongDateTime(date
);
190 if (schema
->hasAttribute(recordType
, kSecCreationDateItemAttr
))
192 setAttribute(schema
->attributeInfoFor(recordType
, kSecCreationDateItemAttr
), date
);
195 if (schema
->hasAttribute(recordType
, kSecModDateItemAttr
))
197 setAttribute(schema
->attributeInfoFor(recordType
, kSecModDateItemAttr
), date
);
200 // If the label (PrintName) attribute isn't specified, set a default label.
201 if (!mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
)))
203 CssmDbAttributeData
*label
= NULL
;
206 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
207 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
210 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
211 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
212 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServerItemAttr
));
213 // if AppleShare server name wasn't specified, try the server address
214 if (!label
) label
= mDbAttributes
->find(Schema::attributeInfo(kSecAddressItemAttr
));
220 // if all else fails, use the account name.
222 label
= mDbAttributes
->find(Schema::attributeInfo(kSecAccountItemAttr
));
224 if (label
&& label
->size())
225 setAttribute (Schema::attributeInfo(kSecLabelItemAttr
), label
->at
<CssmData
>(0));
228 // get the attributes that are part of the primary key
229 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfos
=
230 keychain
->primaryKeyInfosFor(recordType
);
232 // make sure each primary key element has a value in the item, otherwise
233 // the database will complain. we make a set of the provided attribute infos
234 // to avoid O(N^2) behavior.
236 DbAttributes
*attributes
= mDbAttributes
.get();
237 typedef set
<CssmDbAttributeInfo
> InfoSet
;
240 // make a set of all the attributes in the key
241 for (uint32 i
= 0; i
< attributes
->size(); i
++)
242 infoSet
.insert(attributes
->at(i
).Info
);
244 for (uint32 i
= 0; i
< primaryKeyInfos
.size(); i
++) { // check to make sure all required attributes are in the key
245 InfoSet::const_iterator it
= infoSet
.find(primaryKeyInfos
.at(i
));
247 if (it
== infoSet
.end()) { // not in the key? add the default
248 // we need to add a default value to the item attributes
249 attributes
->add(primaryKeyInfos
.at(i
), defaultAttributeValue(primaryKeyInfos
.at(i
)));
253 Db
db(keychain
->database());
254 if (useSecureStorage(db
))
256 // Add the item to the secure storage db
257 SSDb
ssDb(safe_cast
<SSDbImpl
*>(&(*db
)));
259 TrackingAllocator
allocator(CssmAllocator::standard());
261 // hhs replaced with the new aclFactory class
262 AclFactory aclFactory
;
263 const AccessCredentials
*nullCred
= aclFactory
.nullCred();
265 RefPointer
<Access
> access
= mAccess
;
267 // create default access controls for the new item
268 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
));
269 string printName
= data
? CssmData::overlay(data
->Value
[0]).toString() : "keychain item";
270 access
= new Access(printName
);
272 // special case for "iTools" password - allow anyone to decrypt the item
273 if (recordType
== CSSM_DL_DB_RECORD_GENERIC_PASSWORD
)
275 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
276 if (data
&& data
->Value
[0].Length
== 6 && !memcmp("iTools", data
->Value
[0].Data
, 6))
278 typedef vector
<RefPointer
<ACL
> > AclSet
;
280 access
->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT
, acls
);
281 for (AclSet::const_iterator it
= acls
.begin(); it
!= acls
.end(); it
++)
282 (*it
)->form(ACL::allowAllForm
);
287 // Create a new SSGroup with temporary access controls
289 ResourceControlContext prototype
;
290 maker
.initialOwner(prototype
, nullCred
);
291 SSGroup
ssGroup(ssDb
, &prototype
);
295 // Insert the record using the newly created group.
296 mUniqueId
= ssDb
->insert(recordType
, mDbAttributes
.get(),
297 mData
.get(), ssGroup
, maker
.cred());
301 ssGroup
->deleteKey(nullCred
);
305 // now finalize the access controls on the group
306 access
->setAccess(*ssGroup
, maker
);
307 mAccess
= NULL
; // use them and lose them
311 // add the item to the (regular) db
312 mUniqueId
= db
->insert(recordType
, mDbAttributes
.get(), mData
.get());
315 mPrimaryKey
= keychain
->makePrimaryKey(recordType
, mUniqueId
);
316 mKeychain
= keychain
;
318 // Forget our data and attributes.
320 mDbAttributes
.reset(NULL
);
326 ItemImpl::copyTo(const Keychain
&keychain
, Access
*newAccess
/* = NULL */)
330 item
->setAccess(newAccess
);
339 MacOSError::throwMe(errSecNoSuchKeychain
);
341 // Don't update if nothing changed.
345 CSSM_DB_RECORDTYPE aRecordType
= recordType();
346 KeychainSchema schema
= mKeychain
->keychainSchema();
348 // Update the modification date on the item if there is a mod date attribute.
349 if (schema
->hasAttribute(aRecordType
, kSecModDateItemAttr
))
352 GetCurrentMacLongDateTime(date
);
353 setAttribute(schema
->attributeInfoFor(aRecordType
, kSecModDateItemAttr
), date
);
356 // Make sure that we have mUniqueId
358 Db
db(mUniqueId
->database());
359 if (useSecureStorage(db
))
361 // Add the item to the secure storage db
362 SSDbUniqueRecord
ssUniqueId(safe_cast
<SSDbUniqueRecordImpl
*>
365 // @@@ Share this instance
366 const AccessCredentials
*autoPrompt
= globals().credentials();
369 // Only call this is user interaction is enabled.
370 ssUniqueId
->modify(aRecordType
,
373 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
,
378 mUniqueId
->modify(aRecordType
,
381 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
384 PrimaryKey oldPK
= mPrimaryKey
;
385 mPrimaryKey
= mKeychain
->makePrimaryKey(aRecordType
, mUniqueId
);
387 // Forget our data and attributes.
389 mDbAttributes
.reset(NULL
);
391 // Let the Keychain update what it needs to.
392 mKeychain
->didUpdate(this, oldPK
, mPrimaryKey
);
396 ItemImpl::getClass(SecKeychainAttribute
&attr
, UInt32
*actualLength
)
399 *actualLength
= sizeof(SecItemClass
);
401 if (attr
.length
< sizeof(SecItemClass
))
402 MacOSError::throwMe(errSecBufferTooSmall
);
404 SecItemClass aClass
= Schema::itemClassFor(recordType());
405 memcpy(attr
.data
, &aClass
, sizeof(SecItemClass
));
409 ItemImpl::setAttribute(SecKeychainAttribute
& attr
)
411 setAttribute(Schema::attributeInfo(attr
.tag
), CssmData(attr
.data
, attr
.length
));
415 ItemImpl::recordType() const
417 if (mDbAttributes
.get())
418 return mDbAttributes
->recordType();
420 return mPrimaryKey
->recordType();
424 ItemImpl::modifiedAttributes() const
426 return mDbAttributes
.get();
430 ItemImpl::modifiedData() const
436 ItemImpl::setData(UInt32 length
,const void *data
)
438 mData
.reset(new CssmDataContainer(data
, length
));
442 ItemImpl::setAccess(Access
*newAccess
)
447 CssmClient::DbUniqueRecord
448 ItemImpl::dbUniqueRecord()
452 DbCursor
cursor(mPrimaryKey
->createCursor(mKeychain
));
453 if (!cursor
->next(NULL
, NULL
, mUniqueId
))
454 MacOSError::throwMe(errSecInvalidItemRef
);
461 ItemImpl::primaryKey() const
467 ItemImpl::isPersistant() const
473 ItemImpl::isModified() const
475 return mData
.get() || mDbAttributes
.get();
479 ItemImpl::keychain() const
485 ItemImpl::operator <(const ItemImpl
&other
) const
491 return this < &other
;
494 // XXX Deal with not having a mPrimaryKey
495 return *mPrimaryKey
< *(other
.mPrimaryKey
);
500 ItemImpl::setAttribute(const CssmDbAttributeInfo
&info
, const CssmPolyData
&data
)
502 if (!mDbAttributes
.get())
504 mDbAttributes
.reset(new DbAttributes());
505 mDbAttributes
->recordType(mPrimaryKey
->recordType());
508 uint32 length
= data
.Length
;
509 const void *buf
= reinterpret_cast<const void *>(data
.Data
);
510 uint8 timeString
[16];
512 // XXX This code is duplicated in KCCursorImpl::KCCursorImpl()
513 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
514 // style attribute value.
515 if (info
.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
517 if (length
== sizeof(UInt32
))
519 MacSecondsToTimeString(*reinterpret_cast<const UInt32
*>(buf
), 16, &timeString
);
523 else if (length
== sizeof(SInt64
))
525 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64
*>(buf
), 16, &timeString
);
531 mDbAttributes
->add(info
, CssmData(const_cast<void*>(buf
), length
));
535 ItemImpl::modifyContent(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
537 if (!mDbAttributes
.get())
539 mDbAttributes
.reset(new DbAttributes());
540 mDbAttributes
->recordType(mPrimaryKey
->recordType());
543 if(attrList
) // optional
545 for(UInt32 ix
=0; ix
< attrList
->count
; ix
++)
547 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[ix
].tag
), CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
553 mData
.reset(new CssmDataContainer(inData
, dataLength
));
560 ItemImpl::getContent(SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
563 // If the data hasn't been set we can't return it.
564 if (!mKeychain
&& outData
)
566 CssmData
*data
= mData
.get();
568 MacOSError::throwMe(errSecDataNotAvailable
);
570 // TODO: need to check and make sure attrs are valid and handle error condition
574 *itemClass
= Schema::itemClassFor(recordType());
576 bool getDataFromDatabase
= mKeychain
&& mPrimaryKey
;
578 if (getDataFromDatabase
) // are we attached to a database?
584 // get the number of attributes requested by the caller
585 UInt32 attrCount
= attrList
? attrList
->count
: 0;
587 if (getDataFromDatabase
)
589 // make a DBAttributes structure and populate it
590 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
591 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
593 dbAttributes
.add(Schema::attributeInfo(attrList
->attr
[ix
].tag
));
596 // request the data from the database (since we are a reference "item" and the data is really stored there)
597 CssmDataContainer itemData
;
598 if (getDataFromDatabase
)
600 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
603 // retrieve the data from result
604 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
606 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
608 attrList
->attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
609 attrList
->attr
[ix
].length
= dbAttributes
.at(ix
).Value
[0].Length
;
611 // We don't want the data released, it is up the client
612 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
613 dbAttributes
.at(ix
).Value
[0].Length
= 0;
617 attrList
->attr
[ix
].data
= NULL
;
618 attrList
->attr
[ix
].length
= 0;
625 *outData
=itemData
.data();
628 *length
=itemData
.length();
632 else if (attrList
!= NULL
)
634 getLocalContent (*attrList
);
639 // inform anyone interested that we are doing this
640 #if SENDACCESSNOTIFICATIONS
643 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
649 ItemImpl::freeContent(SecKeychainAttributeList
*attrList
, void *data
)
651 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
653 allocator
.free(data
);
655 UInt32 attrCount
= attrList
? attrList
->count
: 0;
656 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
658 allocator
.free(attrList
->attr
[ix
].data
);
659 attrList
->attr
[ix
].data
= NULL
;
664 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
667 MacOSError::throwMe(errSecNoSuchKeychain
);
669 if (!mDbAttributes
.get())
671 mDbAttributes
.reset(new DbAttributes());
672 mDbAttributes
->recordType(mPrimaryKey
->recordType());
675 CSSM_DB_RECORDTYPE recordType
= mDbAttributes
->recordType();
676 UInt32 attrCount
= attrList
? attrList
->count
: 0;
677 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
679 CssmDbAttributeInfo info
=mKeychain
->attributeInfoFor(recordType
, attrList
->attr
[ix
].tag
);
681 if (attrList
->attr
[ix
].length
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
682 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
683 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
)
684 mDbAttributes
->add(info
, CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
686 mDbAttributes
->add(info
);
691 mData
.reset(new CssmDataContainer(inData
, dataLength
));
698 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
700 // If the data hasn't been set we can't return it.
701 if (!mKeychain
&& outData
)
703 CssmData
*data
= mData
.get();
705 MacOSError::throwMe(errSecDataNotAvailable
);
707 // TODO: need to check and make sure attrs are valid and handle error condition
711 *itemClass
= Schema::itemClassFor(recordType());
715 UInt32 attrCount
= info
? info
->count
: 0;
716 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
717 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
719 CssmDbAttributeData
&record
= dbAttributes
.add();
720 record
.Info
.AttributeNameFormat
=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
;
721 record
.Info
.Label
.AttributeID
=info
->tag
[ix
];
724 CssmDataContainer itemData
;
725 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
729 SecKeychainAttributeList
*theList
=reinterpret_cast<SecKeychainAttributeList
*>(malloc(sizeof(SecKeychainAttributeList
)));
730 SecKeychainAttribute
*attr
=reinterpret_cast<SecKeychainAttribute
*>(malloc(sizeof(SecKeychainAttribute
)*attrCount
));
731 theList
->count
=attrCount
;
734 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
736 attr
[ix
].tag
=info
->tag
[ix
];
738 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
740 attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
741 attr
[ix
].length
= dbAttributes
.at(ix
).Value
[0].Length
;
743 // We don't want the data released, it is up the client
744 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
745 dbAttributes
.at(ix
).Value
[0].Length
= 0;
749 attr
[ix
].data
= NULL
;
758 *outData
=itemData
.data();
761 *length
=itemData
.length();
764 #if SENDACCESSNOTIFICATIONS
765 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
772 ItemImpl::freeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
774 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
777 allocator
.free(data
);
781 for (UInt32 ix
= 0; ix
< attrList
->count
; ++ix
)
783 allocator
.free(attrList
->attr
[ix
].data
);
785 free(attrList
->attr
);
791 ItemImpl::getAttribute(SecKeychainAttribute
& attr
, UInt32
*actualLength
)
793 if (attr
.tag
== kSecClassItemAttr
)
794 return getClass(attr
, actualLength
);
796 if (mDbAttributes
.get())
798 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(attr
.tag
));
801 getAttributeFrom(data
, attr
, actualLength
);
807 MacOSError::throwMe(errSecNoSuchAttr
);
810 DbAttributes
dbAttributes(mUniqueId
->database(), 1);
811 dbAttributes
.add(Schema::attributeInfo(attr
.tag
));
812 mUniqueId
->get(&dbAttributes
, NULL
);
813 getAttributeFrom(&dbAttributes
.at(0), attr
, actualLength
);
817 ItemImpl::getAttributeFrom(CssmDbAttributeData
*data
, SecKeychainAttribute
&attr
, UInt32
*actualLength
)
819 static const uint32 zero
= 0;
823 // Temporary storage for buf.
833 else if (data
->size() < 1) // Attribute has no values.
835 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
836 || data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
838 length
= sizeof(zero
);
841 else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
842 length
= 0; // Should we throw here?
843 else // All other formats
846 else // Get the first value
848 length
= data
->Value
[0].Length
;
849 buf
= data
->Value
[0].Data
;
851 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
)
853 if (attr
.length
== sizeof(sint8
))
855 length
= attr
.length
;
856 svalue8
= sint8(*reinterpret_cast<const sint32
*>(buf
));
859 else if (attr
.length
== sizeof(sint16
))
861 length
= attr
.length
;
862 svalue16
= sint16(*reinterpret_cast<const sint32
*>(buf
));
866 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
868 if (attr
.length
== sizeof(uint8
))
870 length
= attr
.length
;
871 uvalue8
= uint8(*reinterpret_cast<const uint32
*>(buf
));
874 else if (attr
.length
== sizeof(uint16
))
876 length
= attr
.length
;
877 uvalue16
= uint16(*reinterpret_cast<const uint32
*>(buf
));
881 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
883 if (attr
.length
== sizeof(UInt32
))
885 TimeStringToMacSeconds(data
->Value
[0], macSeconds
);
887 length
= attr
.length
;
889 else if (attr
.length
== sizeof(SInt64
))
891 TimeStringToMacLongDateTime(data
->Value
[0], macLDT
);
893 length
= attr
.length
;
899 *actualLength
= length
;
903 if (attr
.length
< length
)
904 MacOSError::throwMe(errSecBufferTooSmall
);
906 memcpy(attr
.data
, buf
, length
);
911 ItemImpl::getData(CssmDataContainer
& outData
)
915 CssmData
*data
= mData
.get();
916 // If the data hasn't been set we can't return it.
918 MacOSError::throwMe(errSecDataNotAvailable
);
924 getContent(NULL
, &outData
);
926 #if SENDACCESSNOTIFICATIONS
927 //%%%<might> be done elsewhere, but here is good for now
928 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
938 Db
db(mKeychain
->database());
939 if (useSecureStorage(db
))
941 group
= safer_cast
<SSDbUniqueRecordImpl
&>(*mUniqueId
).group();
948 void ItemImpl::getLocalContent(SecKeychainAttributeList
&attributeList
)
950 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
952 // pull attributes out of a "floating" item, i.e. one that isn't attached to a database
954 for (i
= 0; i
< attributeList
.count
; ++i
)
956 // get the size of the attribute
958 SecKeychainAttribute attribute
;
959 attribute
.tag
= attributeList
.attr
[i
].tag
;
960 attribute
.length
= 0;
961 attribute
.data
= NULL
;
962 getAttribute (attribute
, &actualLength
);
964 // if we didn't get the actual length, mark zeros.
965 if (actualLength
== 0)
967 attributeList
.attr
[i
].length
= 0;
968 attributeList
.attr
[i
].data
= NULL
;
972 // make room in the item data
973 attributeList
.attr
[i
].length
= actualLength
;
974 attributeList
.attr
[i
].data
= allocator
.malloc(actualLength
);
975 getAttribute(attributeList
.attr
[i
], &actualLength
);
981 ItemImpl::getContent(DbAttributes
*dbAttributes
, CssmDataContainer
*itemData
)
983 // Make sure mUniqueId is set.
987 Db
db(mUniqueId
->database());
988 if (useSecureStorage(db
))
990 SSDbUniqueRecord
ssUniqueId(safe_cast
<SSDbUniqueRecordImpl
*>(&(*mUniqueId
)));
991 const AccessCredentials
*autoPrompt
= globals().credentials();
992 ssUniqueId
->get(dbAttributes
, itemData
, autoPrompt
);
997 mUniqueId
->get(dbAttributes
, itemData
);
1001 ItemImpl::useSecureStorage(const Db
&db
)
1003 switch (recordType())
1005 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
1006 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
1007 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
1008 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
1019 // Item -- This class is here to magically create the right subclass of ItemImpl
1020 // when constructing new items.
1026 Item::Item(ItemImpl
*impl
) : RefPointer
<ItemImpl
>(impl
)
1030 Item::Item(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
)
1032 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
1033 || itemClass
== CSSM_DL_DB_RECORD_PUBLIC_KEY
1034 || itemClass
== CSSM_DL_DB_RECORD_PRIVATE_KEY
1035 || itemClass
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1036 MacOSError::throwMe(errSecNoSuchClass
); /* @@@ errSecInvalidClass */
1038 *this = new ItemImpl(itemClass
, itemCreator
, length
, data
);
1041 Item::Item(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
1043 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
1044 || itemClass
== CSSM_DL_DB_RECORD_PUBLIC_KEY
1045 || itemClass
== CSSM_DL_DB_RECORD_PRIVATE_KEY
1046 || itemClass
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1047 MacOSError::throwMe(errSecNoSuchClass
); /* @@@ errSecInvalidClass */
1049 *this = new ItemImpl(itemClass
, attrList
, length
, data
);
1052 Item::Item(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
)
1053 : RefPointer
<ItemImpl
>(
1054 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1055 ? new Certificate(keychain
, primaryKey
, uniqueId
)
1056 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1057 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1058 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1059 ? new KeyItem(keychain
, primaryKey
, uniqueId
)
1060 : new ItemImpl(keychain
, primaryKey
, uniqueId
))
1064 Item::Item(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
1065 : RefPointer
<ItemImpl
>(
1066 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1067 ? new Certificate(keychain
, primaryKey
)
1068 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1069 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1070 || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1071 ? new KeyItem(keychain
, primaryKey
)
1072 : new ItemImpl(keychain
, primaryKey
))
1076 Item::Item(ItemImpl
&item
)
1077 : RefPointer
<ItemImpl
>(
1078 item
.recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1079 ? new Certificate(safer_cast
<Certificate
&>(item
))
1080 : (item
.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1081 || item
.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1082 || item
.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
1083 ? new KeyItem(safer_cast
<KeyItem
&>(item
))
1084 : new ItemImpl(item
))