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.
27 #include "KCEventNotifier.h"
28 #include "cssmdatetime.h"
29 #include <Security/keychainacl.h>
30 #include <Security/SecKeychainAPIPriv.h>
31 #include <Security/aclsupport.h>
32 #include <Security/osxsigning.h>
34 using namespace KeychainCore
;
35 using namespace CSSMDateTimeUtils
;
41 // NewItemImpl constructor
42 ItemImpl::ItemImpl(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
)
43 : mDbAttributes(new DbAttributes())
46 mData
.reset(new CssmDataContainer(data
, length
));
48 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
49 mDbAttributes
->add(Schema::attributeInfo(kSecCreatorItemAttr
), itemCreator
);
52 GetCurrentMacLongDateTime(date
);
53 setAttribute(Schema::attributeInfo(kSecCreationDateItemAttr
), date
);
54 setAttribute(Schema::attributeInfo(kSecModDateItemAttr
), date
);
57 ItemImpl::ItemImpl(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
, UInt32 length
, const void* data
)
58 : mDbAttributes(new DbAttributes())
61 mData
.reset(new CssmDataContainer(data
, length
));
64 mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
));
68 for(UInt32 i
=0; i
< attrList
->count
; i
++)
70 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[i
].tag
), CssmData(attrList
->attr
[i
].data
, attrList
->attr
[i
].length
));
75 GetCurrentMacLongDateTime(date
);
76 setAttribute(Schema::attributeInfo(kSecCreationDateItemAttr
), date
);
77 setAttribute(Schema::attributeInfo(kSecModDateItemAttr
), date
);
80 // DbItemImpl constructor
81 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const DbUniqueRecord
&uniqueId
)
82 : mUniqueId(uniqueId
), mKeychain(keychain
), mPrimaryKey(primaryKey
)
84 mKeychain
->addItem(mPrimaryKey
, this);
87 // PrimaryKey ItemImpl constructor
88 ItemImpl::ItemImpl(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
89 : mKeychain(keychain
), mPrimaryKey(primaryKey
)
91 mKeychain
->addItem(mPrimaryKey
, this);
94 // Constructor used when copying an item to a keychain.
96 ItemImpl::ItemImpl(ItemImpl
&item
) :
97 mData(item
.modifiedData() ? NULL
: new CssmDataContainer()),
98 mDbAttributes(new DbAttributes())
100 mDbAttributes
->recordType(item
.recordType());
101 CSSM_DB_RECORD_ATTRIBUTE_INFO
*schemaAttributes
= NULL
;
103 if (item
.mKeychain
) {
104 // get the entire source item from its keychain. This requires figuring
105 // out the schema for the item based on its record type.
107 for (uint32 i
= 0; i
< Schema::DBInfo
.NumberOfRecordTypes
; i
++)
108 if (item
.recordType() == Schema::DBInfo
.RecordAttributeNames
[i
].DataRecordType
) {
109 schemaAttributes
= &Schema::DBInfo
.RecordAttributeNames
[i
];
113 if (schemaAttributes
== NULL
)
114 // the source item is invalid
115 MacOSError::throwMe(errSecInvalidItemRef
);
117 for (uint32 i
= 0; i
< schemaAttributes
->NumberOfAttributes
; i
++)
118 mDbAttributes
->add(schemaAttributes
->AttributeInfo
[i
]);
120 item
.getContent(mDbAttributes
.get(), mData
.get());
123 // @@@ We don't deal with modified attributes.
125 if (item
.modifiedData())
126 // the copied data comes from the source item
127 mData
.reset(new CssmDataContainer(item
.modifiedData()->Data
,
128 item
.modifiedData()->Length
));
131 ItemImpl::~ItemImpl()
133 if (mKeychain
&& *mPrimaryKey
)
134 mKeychain
->removeItem(*mPrimaryKey
, this);
138 ItemImpl::didModify()
141 mDbAttributes
.reset(NULL
);
145 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO
&info
)
147 static const uint32 zeroInt
= 0;
148 static const double zeroDouble
= 0.0;
149 static const char timeBytes
[] = "20010101000000Z";
151 static const CSSM_DATA defaultFourBytes
= { 4, (uint8
*) &zeroInt
};
152 static const CSSM_DATA defaultEightBytes
= { 8, (uint8
*) &zeroDouble
};
153 static const CSSM_DATA defaultTime
= { 16, (uint8
*) timeBytes
};
154 static const CSSM_DATA defaultZeroBytes
= { 0, NULL
};
156 switch (info
.AttributeFormat
)
158 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
:
159 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
:
160 return defaultFourBytes
;
162 case CSSM_DB_ATTRIBUTE_FORMAT_REAL
:
163 return defaultEightBytes
;
165 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
:
169 return defaultZeroBytes
;
174 ItemImpl::add(const Keychain
&keychain
)
176 // If we already have a Keychain we can't be added.
178 MacOSError::throwMe(errSecDuplicateItem
);
180 // If we don't have any attributes we can't be added.
181 // (this might occur if attempting to add the item twice, since our attributes
182 // and data are set to NULL at the end of this function.)
183 if (!mDbAttributes
.get())
184 MacOSError::throwMe(errSecDuplicateItem
);
186 // If the label (PrintName) attribute isn't specified, set a default label.
187 if (!mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
)))
189 CssmDbAttributeData
*label
= NULL
;
190 switch (mDbAttributes
->recordType())
192 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
193 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
196 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
197 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
198 label
= mDbAttributes
->find(Schema::attributeInfo(kSecServerItemAttr
));
199 // if AppleShare server name wasn't specified, try the server address
200 if (!label
) label
= mDbAttributes
->find(Schema::attributeInfo(kSecAddressItemAttr
));
206 // if all else fails, use the account name.
207 if (!label
) label
= mDbAttributes
->find(Schema::attributeInfo(kSecAccountItemAttr
));
209 if (label
&& label
->size())
210 mDbAttributes
->add(Schema::attributeInfo(kSecLabelItemAttr
), label
->at
<CssmData
>(0));
213 // get the attributes that are part of the primary key
214 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfos
=
215 keychain
->primaryKeyInfosFor(recordType());
217 // make sure each primary key element has a value in the item, otherwise
218 // the database will complain. we make a set of the provided attribute infos
219 // to avoid O(N^2) behavior.
221 DbAttributes
*attributes
= mDbAttributes
.get();
222 typedef set
<CssmDbAttributeInfo
> InfoSet
;
225 for (uint32 i
= 0; i
< attributes
->size(); i
++)
226 infoSet
.insert(attributes
->at(i
).Info
);
228 for (uint32 i
= 0; i
< primaryKeyInfos
.size(); i
++) {
229 InfoSet::const_iterator it
= infoSet
.find(primaryKeyInfos
.at(i
));
231 if (it
== infoSet
.end()) {
232 // we need to add a default value to the item attributes
233 attributes
->add(primaryKeyInfos
.at(i
),
234 defaultAttributeValue(primaryKeyInfos
.at(i
)));
238 Db
db(keychain
->database());
239 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
241 // Add the item to the secure storage db
242 SSDb
ssDb(safe_cast
<SSDbImpl
*>(&(*db
)));
244 TrackingAllocator
allocator(CssmAllocator::standard());
245 // @@@ Share this instance
246 KeychainAclFactory
aclFactory(allocator
);
248 AclEntryPrototype
anyEncrypt(TypedList(allocator
, CSSM_ACL_SUBJECT_TYPE_ANY
));
249 AuthorizationGroup
&anyEncryptAuthGroup
= anyEncrypt
.authorization();
250 CSSM_ACL_AUTHORIZATION_TAG encryptTag
= CSSM_ACL_AUTHORIZATION_ENCRYPT
;
251 anyEncryptAuthGroup
.NumberOfAuthTags
= 1;
252 anyEncryptAuthGroup
.AuthTags
= &encryptTag
;
254 const AccessCredentials
*nullCred
= aclFactory
.nullCredentials();
256 const ResourceControlContext credAndAclEntry
257 (anyEncrypt
, const_cast<AccessCredentials
*>(nullCred
));
259 // Create a new SSGroup with owner = ANY, encrypt = ANY
260 SSGroup
ssGroup(ssDb
, &credAndAclEntry
);
262 // Now we edit the acl to look like we want it to.
264 // Find the PrintName (which we want SecurityAgent to display when evaluating the ACL
265 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
));
267 CssmData
&printName
= data
? CssmData::overlay(data
->Value
[0]) : noName
;
269 // @@@ This code should use KeychainACL instead, but that class will need some changes.
270 // Defering integration with KeychainACL to Puma.
272 // Figure out if we should special case this to have an anyAllow in this ACL or not.
273 // Currently only generic password items with sevicename "iTools" passwords are always anyAllow.
274 bool anyAllow
= false;
275 if (mDbAttributes
->recordType() == CSSM_DL_DB_RECORD_GENERIC_PASSWORD
)
277 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
));
278 if (data
&& data
->Value
[0].Length
== 6 && !memcmp("iTools", data
->Value
[0].Data
, 6))
282 CssmList
&list
= *new(allocator
) CssmList();
284 // List is a threshold acl with 2 elements or 3 if anyAllow is true.
285 list
.append(new(allocator
) ListElement(CSSM_ACL_SUBJECT_TYPE_THRESHOLD
));
286 list
.append(new(allocator
) ListElement(1));
287 list
.append(new(allocator
) ListElement(2 + anyAllow
));
289 // If anyAllow is true start the threshold list with a any allow sublist.
292 CssmList
&anySublist
= *new(allocator
) CssmList();
293 anySublist
.append(new(allocator
) ListElement(CSSM_ACL_SUBJECT_TYPE_ANY
));
294 list
.append(new(allocator
) ListElement(anySublist
));
297 // Now add a sublist to trust the current application.
298 auto_ptr
<CodeSigning::OSXCode
> code(CodeSigning::OSXCode::main());
299 const char *path
= code
->canonicalPath().c_str();
300 CssmData
comment(const_cast<char *>(path
), strlen(path
) + 1);
301 TrustedApplication
app(path
, comment
);
302 CssmList
&appSublist
= *new(allocator
) CssmList();
303 appSublist
.append(new(allocator
) ListElement(CSSM_ACL_SUBJECT_TYPE_CODE_SIGNATURE
));
304 appSublist
.append(new(allocator
) ListElement(CSSM_ACL_CODE_SIGNATURE_OSX
));
305 appSublist
.append(new(allocator
) ListElement(app
->signature()));
306 appSublist
.append(new(allocator
) ListElement(app
->comment()));
307 list
.append(new(allocator
) ListElement(appSublist
));
309 // Finally add the keychain prompt sublist to the list so we default to asking
310 // the user for permission if all else fails.
311 CssmList
&promptSublist
= *new(allocator
) CssmList();
312 promptSublist
.append(new(allocator
) ListElement(CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT
));
313 promptSublist
.append(new(allocator
) ListElement(printName
));
314 list
.append(new(allocator
) ListElement(promptSublist
));
316 // The acl prototype we want to add contains the list we just made.
317 AclEntryPrototype
promptDecrypt(list
);
319 // Now make sure it only authorizes decrypt.
320 AuthorizationGroup
&promptDecryptAuthGroup
= promptDecrypt
.authorization();
321 CSSM_ACL_AUTHORIZATION_TAG decryptTag
= CSSM_ACL_AUTHORIZATION_DECRYPT
;
322 promptDecryptAuthGroup
.NumberOfAuthTags
= 1;
323 promptDecryptAuthGroup
.AuthTags
= &decryptTag
;
325 // Add an acl entry for decrypt we just made
326 AclEdit
edit(promptDecrypt
);
327 ssGroup
->changeAcl(nullCred
, edit
);
331 // Insert the record using the newly created group.
332 mUniqueId
= ssDb
->insert(recordType(), mDbAttributes
.get(),
333 mData
.get(), ssGroup
, nullCred
);
337 ssGroup
->deleteKey(nullCred
);
341 // Change the owner so change acl = KeychainPrompt
342 AclEntryPrototype
promptOwner(TypedList(allocator
, CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT
,
343 new(allocator
) ListElement(allocator
, printName
)));
344 AclOwnerPrototype
owner(promptOwner
);
345 ssGroup
->changeOwner(nullCred
, owner
);
349 // add the item to the (regular) db
350 mUniqueId
= db
->insert(recordType(), mDbAttributes
.get(), mData
.get());
353 mPrimaryKey
= keychain
->makePrimaryKey(recordType(), mUniqueId
);
354 mKeychain
= keychain
;
356 // Forget our data and attributes.
358 mDbAttributes
.reset(NULL
);
364 ItemImpl::copyTo(const Keychain
&keychain
)
375 MacOSError::throwMe(errSecNoSuchKeychain
);
377 // Don't update if nothing changed.
381 // Set the modification date on the item.
383 GetCurrentMacLongDateTime(date
);
384 setAttribute(Schema::attributeInfo(kSecModDateItemAttr
), date
);
386 // Make sure that we have mUniqueId
388 Db
db(mUniqueId
->database());
389 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
391 // Add the item to the secure storage db
392 SSDbUniqueRecord
ssUniqueId(safe_cast
<SSDbUniqueRecordImpl
*>
395 // @@@ Share this instance
396 const AccessCredentials
*autoPrompt
= globals().credentials();
399 // Only call this is user interaction is enabled.
400 ssUniqueId
->modify(recordType(),
403 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
,
408 mUniqueId
->modify(recordType(),
411 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
414 PrimaryKey oldPK
= mPrimaryKey
;
415 mPrimaryKey
= mKeychain
->makePrimaryKey(recordType(), mUniqueId
);
417 // Forget our data and attributes.
419 mDbAttributes
.reset(NULL
);
421 // Let the Keychain update what it needs to.
422 mKeychain
->didUpdate(this, oldPK
, mPrimaryKey
);
426 ItemImpl::getClass(SecKeychainAttribute
&attr
, UInt32
*actualLength
)
429 *actualLength
= sizeof(SecItemClass
);
431 if (attr
.length
< sizeof(SecItemClass
))
432 MacOSError::throwMe(errSecBufferTooSmall
);
434 SecItemClass aClass
= Schema::itemClassFor(recordType());
435 memcpy(attr
.data
, &aClass
, sizeof(SecItemClass
));
439 ItemImpl::setAttribute(SecKeychainAttribute
& attr
)
441 setAttribute(Schema::attributeInfo(attr
.tag
), CssmData(attr
.data
, attr
.length
));
445 ItemImpl::recordType() const
447 if (mDbAttributes
.get())
448 return mDbAttributes
->recordType();
450 return mPrimaryKey
->recordType();
454 ItemImpl::modifiedAttributes() const
456 return mDbAttributes
.get();
460 ItemImpl::modifiedData() const
466 ItemImpl::setData(UInt32 length
,const void *data
)
468 mData
.reset(new CssmDataContainer(data
, length
));
471 CssmClient::DbUniqueRecord
472 ItemImpl::dbUniqueRecord()
476 assert(mKeychain
&& mPrimaryKey
);
477 DbCursor
cursor(mPrimaryKey
->createCursor(mKeychain
));
478 if (!cursor
->next(NULL
, NULL
, mUniqueId
))
481 MacOSError::throwMe(errSecInvalidItemRef
);
489 ItemImpl::primaryKey() const
495 ItemImpl::isPersistant() const
501 ItemImpl::isModified() const
503 return mData
.get() || mDbAttributes
.get();
507 ItemImpl::keychain() const
513 ItemImpl::operator <(const ItemImpl
&other
) const
519 return this < &other
;
522 // XXX Deal with not having a mPrimaryKey
523 return *mPrimaryKey
< *(other
.mPrimaryKey
);
528 ItemImpl::setAttribute(const CssmDbAttributeInfo
&info
, const CssmPolyData
&data
)
530 if (!mDbAttributes
.get())
532 mDbAttributes
.reset(new DbAttributes());
533 mDbAttributes
->recordType(mPrimaryKey
->recordType());
536 uint32 length
= data
.Length
;
537 const void *buf
= reinterpret_cast<const void *>(data
.Data
);
538 uint8 timeString
[16];
540 // XXX This code is duplicated in KCCursorImpl::KCCursorImpl()
541 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
542 // style attribute value.
543 if (info
.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
545 if (length
== sizeof(UInt32
))
547 MacSecondsToTimeString(*reinterpret_cast<const UInt32
*>(buf
), 16, &timeString
);
551 else if (length
== sizeof(SInt64
))
553 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64
*>(buf
),
560 mDbAttributes
->add(info
, CssmData(const_cast<void*>(buf
), length
));
564 ItemImpl::modifyContent(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
566 if (!mDbAttributes
.get())
568 mDbAttributes
.reset(new DbAttributes());
569 mDbAttributes
->recordType(mPrimaryKey
->recordType());
572 if(attrList
) // optional
574 for(UInt32 ix
=0; ix
< attrList
->count
; ix
++)
576 mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[ix
].tag
), CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
582 mData
.reset(new CssmDataContainer(inData
, dataLength
));
589 ItemImpl::getContent(SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
592 // If the data hasn't been set we can't return it.
593 if (!mKeychain
&& outData
)
595 CssmData
*data
= mData
.get();
597 MacOSError::throwMe(errSecDataNotAvailable
);
599 // TODO: need to check and make sure attrs are valid and handle error condition
603 *itemClass
= Schema::itemClassFor(recordType());
607 UInt32 attrCount
= attrList
? attrList
->count
: 0;
608 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
609 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
610 dbAttributes
.add(Schema::attributeInfo(attrList
->attr
[ix
].tag
));
612 CssmDataContainer itemData
;
613 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
615 if (outData
) KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
617 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
619 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
621 attrList
->attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
622 attrList
->attr
[ix
].length
= dbAttributes
.at(ix
).Value
[0].Length
;
624 // We don't want the data released, it is up the client
625 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
626 dbAttributes
.at(ix
).Value
[0].Length
= 0;
630 attrList
->attr
[ix
].data
= NULL
;
631 attrList
->attr
[ix
].length
= 0;
637 *outData
=itemData
.data();
640 *length
=itemData
.length();
647 ItemImpl::freeContent(SecKeychainAttributeList
*attrList
, void *data
)
649 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
651 allocator
.free(data
);
653 UInt32 attrCount
= attrList
? attrList
->count
: 0;
654 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
656 allocator
.free(attrList
->attr
[ix
].data
);
657 attrList
->attr
[ix
].data
= NULL
;
662 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList
*attrList
, UInt32 dataLength
, const void *inData
)
665 MacOSError::throwMe(errSecNoSuchKeychain
);
667 if (!mDbAttributes
.get())
669 mDbAttributes
.reset(new DbAttributes());
670 mDbAttributes
->recordType(mPrimaryKey
->recordType());
673 UInt32 attrCount
= attrList
? attrList
->count
: 0;
674 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
676 CssmDbAttributeInfo info
=mKeychain
->attributeInfoForTag(attrList
->attr
[ix
].tag
);
678 if (attrList
->attr
[ix
].length
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
679 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
680 || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
)
681 mDbAttributes
->add(info
, CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
));
683 mDbAttributes
->add(info
);
688 mData
.reset(new CssmDataContainer(inData
, dataLength
));
695 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
697 // If the data hasn't been set we can't return it.
698 if (!mKeychain
&& outData
)
700 CssmData
*data
= mData
.get();
702 MacOSError::throwMe(errSecDataNotAvailable
);
704 // TODO: need to check and make sure attrs are valid and handle error condition
708 *itemClass
= Schema::itemClassFor(recordType());
712 UInt32 attrCount
= info
? info
->count
: 0;
713 DbAttributes
dbAttributes(mUniqueId
->database(), attrCount
);
714 for (UInt32 ix
= 0; ix
< attrCount
; ix
++)
716 CssmDbAttributeData
&record
= dbAttributes
.add();
717 record
.Info
.AttributeNameFormat
=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
;
718 record
.Info
.Label
.AttributeID
=info
->tag
[ix
];
721 CssmDataContainer itemData
;
722 getContent(&dbAttributes
, outData
? &itemData
: NULL
);
726 SecKeychainAttributeList
*theList
=reinterpret_cast<SecKeychainAttributeList
*>(malloc(sizeof(SecKeychainAttributeList
)));
727 SecKeychainAttribute
*attr
=reinterpret_cast<SecKeychainAttribute
*>(malloc(sizeof(SecKeychainAttribute
)*attrCount
));
728 theList
->count
=attrCount
;
731 for (UInt32 ix
= 0; ix
< attrCount
; ++ix
)
733 attr
[ix
].tag
=info
->tag
[ix
];
735 if (dbAttributes
.at(ix
).NumberOfValues
> 0)
737 attr
[ix
].data
= dbAttributes
.at(ix
).Value
[0].Data
;
738 attr
[ix
].length
= dbAttributes
.at(ix
).Value
[0].Length
;
740 // We don't want the data released, it is up the client
741 dbAttributes
.at(ix
).Value
[0].Data
= NULL
;
742 dbAttributes
.at(ix
).Value
[0].Length
= 0;
746 attr
[ix
].data
= NULL
;
755 *outData
=itemData
.data();
758 *length
=itemData
.length();
761 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
767 ItemImpl::freeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
769 CssmAllocator
&allocator
= CssmAllocator::standard(); // @@@ This might not match the one used originally
772 allocator
.free(data
);
776 for (UInt32 ix
= 0; ix
< attrList
->count
; ++ix
)
778 allocator
.free(attrList
->attr
[ix
].data
);
780 free(attrList
->attr
);
786 ItemImpl::getAttribute(SecKeychainAttribute
& attr
, UInt32
*actualLength
)
788 if (attr
.tag
== kSecClassItemAttr
)
789 return getClass(attr
, actualLength
);
791 if (mDbAttributes
.get())
793 CssmDbAttributeData
*data
= mDbAttributes
->find(Schema::attributeInfo(attr
.tag
));
796 getAttributeFrom(data
, attr
, actualLength
);
802 MacOSError::throwMe(errSecNoSuchAttr
);
805 DbAttributes
dbAttributes(mUniqueId
->database(), 1);
806 dbAttributes
.add(Schema::attributeInfo(attr
.tag
));
807 mUniqueId
->get(&dbAttributes
, NULL
);
808 getAttributeFrom(&dbAttributes
.at(0), attr
, actualLength
);
812 ItemImpl::getAttributeFrom(CssmDbAttributeData
*data
, SecKeychainAttribute
&attr
, UInt32
*actualLength
)
814 static const uint32 zero
= 0;
818 // Temporary storage for buf.
828 else if (data
->size() < 1) // Attribute has no values.
830 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
831 || data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
833 length
= sizeof(zero
);
836 else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
837 length
= 0; // Should we throw here?
838 else // All other formats
841 else // Get the first value
843 length
= data
->Value
[0].Length
;
844 buf
= data
->Value
[0].Data
;
846 if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
)
848 if (attr
.length
== sizeof(sint8
))
850 length
= attr
.length
;
851 svalue8
= sint8(*reinterpret_cast<const sint32
*>(buf
));
854 else if (attr
.length
== sizeof(sint16
))
856 length
= attr
.length
;
857 svalue16
= sint16(*reinterpret_cast<const sint32
*>(buf
));
861 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
863 if (attr
.length
== sizeof(uint8
))
865 length
= attr
.length
;
866 uvalue8
= uint8(*reinterpret_cast<const uint32
*>(buf
));
869 else if (attr
.length
== sizeof(uint16
))
871 length
= attr
.length
;
872 uvalue16
= uint16(*reinterpret_cast<const uint32
*>(buf
));
876 else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
)
878 if (attr
.length
== sizeof(UInt32
))
880 TimeStringToMacSeconds(data
->Value
[0], macSeconds
);
882 length
= attr
.length
;
884 else if (attr
.length
== sizeof(SInt64
))
886 TimeStringToMacLongDateTime(data
->Value
[0], macLDT
);
888 length
= attr
.length
;
894 *actualLength
= length
;
898 if (attr
.length
< length
)
899 MacOSError::throwMe(errSecBufferTooSmall
);
901 memcpy(attr
.data
, buf
, length
);
906 ItemImpl::getData(CssmDataContainer
& outData
)
910 CssmData
*data
= mData
.get();
911 // If the data hasn't been set we can't return it.
913 MacOSError::throwMe(errSecDataNotAvailable
);
919 getContent(NULL
, &outData
);
921 //%%%<might> be done elsewhere, but here is good for now
922 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent
, mKeychain
, this);
931 Db
db(mKeychain
->database());
932 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
934 group
= safer_cast
<SSDbUniqueRecordImpl
&>(*mUniqueId
).group();
942 ItemImpl::getContent(DbAttributes
*dbAttributes
, CssmDataContainer
*itemData
)
944 // Make sure mUniqueId is set.
948 Db
db(mUniqueId
->database());
949 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
951 SSDbUniqueRecord
ssUniqueId(safe_cast
<SSDbUniqueRecordImpl
*>(&(*mUniqueId
)));
952 const AccessCredentials
*autoPrompt
= globals().credentials();
953 ssUniqueId
->get(dbAttributes
, itemData
, autoPrompt
);
958 mUniqueId
->get(dbAttributes
, itemData
);