#include "SecBridge.h"
#include <security_utilities/cfutilities.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/SecKeychainItem.h>
#include <Security/SecItem.h>
#include <Security/SecItemPriv.h>
#include <AssertMacros.h>
#define CFDataGetBytePtrVoid CFDataGetBytePtr
#pragma mark SecItem private utility functions
static SecProtocolType
_SecProtocolTypeForSecAttrProtocol(
CFTypeRef protocol)
{
SecProtocolType result = kSecProtocolTypeAny;
if ( protocol != NULL ) {
if ( CFEqual(protocol, kSecAttrProtocolHTTP) ) {
result = kSecProtocolTypeHTTP;
}
else if ( CFEqual(protocol, kSecAttrProtocolHTTPS) ) {
result = kSecProtocolTypeHTTPS;
}
else if ( CFEqual(protocol, kSecAttrProtocolFTP) ) {
result = kSecProtocolTypeFTP;
}
else if ( CFEqual(protocol, kSecAttrProtocolFTPS) ) {
result = kSecProtocolTypeFTPS;
}
else if ( CFEqual(protocol, kSecAttrProtocolHTTPProxy) ) {
result = kSecProtocolTypeHTTPProxy;
}
else if ( CFEqual(protocol, kSecAttrProtocolHTTPSProxy) ) {
result = kSecProtocolTypeHTTPSProxy;
}
else if ( CFEqual(protocol, kSecAttrProtocolFTPProxy) ) {
result = kSecProtocolTypeFTPProxy;
}
else if ( CFEqual(protocol, kSecAttrProtocolSOCKS) ) {
result = kSecProtocolTypeSOCKS;
}
}
return ( result );
}
static CFTypeRef
_SecAttrProtocolForSecProtocolType(
SecProtocolType protocolType)
{
CFTypeRef result;
switch ( protocolType ) {
case kSecProtocolTypeHTTP:
result = kSecAttrProtocolHTTP;
break;
case kSecProtocolTypeHTTPS:
result = kSecAttrProtocolHTTPS;
break;
case kSecProtocolTypeFTP:
result = kSecAttrProtocolFTP;
break;
case kSecProtocolTypeFTPS:
result = kSecAttrProtocolFTPS;
break;
case kSecProtocolTypeHTTPProxy:
result = kSecAttrProtocolHTTPProxy;
break;
case kSecProtocolTypeHTTPSProxy:
result = kSecAttrProtocolHTTPSProxy;
break;
case kSecProtocolTypeFTPProxy:
result = kSecAttrProtocolFTPProxy;
break;
case kSecProtocolTypeSOCKS:
result = kSecAttrProtocolSOCKS;
break;
default:
result = NULL;
break;
}
return ( result );
}
static SecAuthenticationType
_SecAuthenticationTypeForSecAttrAuthenticationType(
CFTypeRef authenticationType)
{
SecAuthenticationType result = kSecAuthenticationTypeAny;
if ( authenticationType != NULL ) {
if ( CFEqual(authenticationType, kSecAttrAuthenticationTypeDefault) ) {
result = kSecAuthenticationTypeDefault;
}
else if ( CFEqual(authenticationType, kSecAttrAuthenticationTypeHTTPBasic) ) {
result = kSecAuthenticationTypeHTTPBasic;
}
else if ( CFEqual(authenticationType, kSecAttrAuthenticationTypeHTTPDigest) ) {
result = kSecAuthenticationTypeHTTPDigest;
}
else if ( CFEqual(authenticationType, kSecAttrAuthenticationTypeHTMLForm) ) {
result = kSecAuthenticationTypeHTMLForm;
}
else if ( CFEqual(authenticationType, kSecAttrAuthenticationTypeNTLM) ) {
result = kSecAuthenticationTypeNTLM;
}
}
return ( result );
}
static CFTypeRef
_SecAttrAuthenticationTypeForSecAuthenticationType(
SecAuthenticationType authenticationType)
{
CFTypeRef result;
switch ( authenticationType ) {
case kSecAuthenticationTypeDefault:
result = kSecAttrAuthenticationTypeDefault;
break;
case kSecAuthenticationTypeHTTPBasic:
result = kSecAttrAuthenticationTypeHTTPBasic;
break;
case kSecAuthenticationTypeHTTPDigest:
result = kSecAttrAuthenticationTypeHTTPDigest;
break;
case kSecAuthenticationTypeHTMLForm:
result = kSecAttrAuthenticationTypeHTMLForm;
break;
case kSecAuthenticationTypeNTLM:
result = kSecAttrAuthenticationTypeNTLM;
break;
default:
result = NULL;
break;
}
return ( result );
}
static OSStatus
_CreateAttributesDictionaryFromItem(
CFAllocatorRef allocator,
SecKeychainItemRef item,
CFDictionaryRef *dictionary)
{
OSStatus status;
SecKeychainAttribute attr[] = {
{ kSecServerItemAttr, 0, NULL },
{ kSecSecurityDomainItemAttr, 0, NULL },
{ kSecAccountItemAttr, 0, NULL },
{ kSecPathItemAttr, 0, NULL },
{ kSecPortItemAttr, 0, NULL },
{ kSecProtocolItemAttr, 0, NULL },
{ kSecAuthenticationTypeItemAttr, 0, NULL },
{ kSecCommentItemAttr, 0, NULL },
{ kSecDescriptionItemAttr, 0, NULL },
{ kSecLabelItemAttr, 0, NULL }
};
SecKeychainAttributeList attrList = { sizeof(attr) / sizeof(SecKeychainAttribute), attr };
CFIndex numValues;
CFIndex index;
CFTypeRef keys[(sizeof(attr) / sizeof(SecKeychainAttribute)) + 2];
CFTypeRef values[(sizeof(attr) / sizeof(SecKeychainAttribute)) + 2];
*dictionary = NULL;
status = SecKeychainItemCopyContent(item, NULL, &attrList, NULL, NULL);
require_noerr(status, SecKeychainItemCopyContent_failed);
numValues = 0;
keys[numValues] = kSecClass;
values[numValues] = kSecClassInternetPassword;
++numValues;
if ( attrList.attr[0].length > 0 ) {
keys[numValues] = kSecAttrServer;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[0].data, attrList.attr[0].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[1].length > 0 ) {
keys[numValues] = kSecAttrSecurityDomain;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[1].data, attrList.attr[1].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[2].length > 0 ) {
keys[numValues] = kSecAttrAccount;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[2].data, attrList.attr[2].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[3].length > 0 ) {
keys[numValues] = kSecAttrPath;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[3].data, attrList.attr[3].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[4].length > 0 ) {
keys[numValues] = kSecAttrPort;
values[numValues] = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[4].data);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[5].length > 0 ) {
keys[numValues] = kSecAttrProtocol;
values[numValues] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType*)attrList.attr[5].data);
if ( values[numValues] != NULL ) {
CFRetain(values[numValues]);
++numValues;
}
}
if ( attrList.attr[6].length > 0 ) {
keys[numValues] = kSecAttrAuthenticationType;
values[numValues] = _SecAttrAuthenticationTypeForSecAuthenticationType(*(SecProtocolType*)attrList.attr[6].data);
if ( values[numValues] != NULL ) {
CFRetain(values[numValues]);
++numValues;
}
}
if ( attrList.attr[7].length > 0 ) {
keys[numValues] = kSecAttrComment;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[7].data, attrList.attr[7].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[8].length > 0 ) {
keys[numValues] = kSecAttrDescription;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[8].data, attrList.attr[8].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
if ( attrList.attr[9].length > 0 ) {
keys[numValues] = kSecAttrLabel;
values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[9].data, attrList.attr[9].length, kCFStringEncodingUTF8, FALSE);
if ( values[numValues] != NULL ) {
++numValues;
}
}
*dictionary = CFDictionaryCreate(allocator, keys, values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for ( index = 0; index < numValues; ++index )
{
CFRelease(values[index]);
}
(void) SecKeychainItemFreeContent(&attrList, NULL);
SecKeychainItemCopyContent_failed:
return ( status );
}
static void
_FreeAttrList(
SecKeychainAttributeList *attrListPtr)
{
UInt32 index;
if ( attrListPtr != NULL ) {
if ( attrListPtr->attr != NULL ) {
for ( index = 0; index < attrListPtr->count; ++index ) {
free(attrListPtr->attr[index].data);
}
free(attrListPtr->attr);
}
free(attrListPtr);
}
}
static OSStatus
_CFStringCreateAttribute(
CFStringRef string,
SecKeychainAttrType tag,
SecKeychainAttributePtr attr)
{
OSStatus status;
CFRange range;
status = noErr;
attr->tag = tag;
range = CFRangeMake(0, CFStringGetLength(string));
CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, FALSE, NULL, 0, (CFIndex *)&attr->length);
attr->data = malloc(attr->length);
require_action(attr->data != NULL, malloc_failed, status = errSecBufferTooSmall);
CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, FALSE, (UInt8 *)attr->data, attr->length, NULL);
malloc_failed:
return ( status );
}
static OSStatus
_CreateSecKeychainAttributeListFromDictionary(
CFDictionaryRef attrDictionary,
SecKeychainAttributeList **attrList)
{
OSStatus status;
CFTypeRef value;
SecKeychainAttributeList *attrListPtr;
attrListPtr = (SecKeychainAttributeList*)calloc(1, sizeof(SecKeychainAttributeList));
require_action(attrListPtr != NULL, calloc_attrListPtr_failed, status = errSecBufferTooSmall);
#define kMaxSecKeychainAttributes 10
attrListPtr->attr = (SecKeychainAttribute*)calloc(kMaxSecKeychainAttributes, sizeof(SecKeychainAttribute));
require_action(attrListPtr->attr != NULL, malloc_attrPtr_failed, status = errSecBufferTooSmall);
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrServer, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecServerItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrSecurityDomain, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecSecurityDomainItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrAccount, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecAccountItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrPath, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecPathItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrPort, (const void **)&value) ) {
attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt16));
require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
attrListPtr->attr[attrListPtr->count].tag = kSecPortItemAttr;
attrListPtr->attr[attrListPtr->count].length = sizeof(UInt16);
CFNumberGetValue((CFNumberRef)value, kCFNumberSInt16Type, attrListPtr->attr[attrListPtr->count].data);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrProtocol, (const void **)&value) ) {
attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(SecProtocolType));
require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_protocol_failed, status = errSecBufferTooSmall);
attrListPtr->attr[attrListPtr->count].tag = kSecProtocolItemAttr;
attrListPtr->attr[attrListPtr->count].length = sizeof(SecProtocolType);
*(SecProtocolType *)(attrListPtr->attr[attrListPtr->count].data) = _SecProtocolTypeForSecAttrProtocol(value);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrAuthenticationType, (const void **)&value) ) {
attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(SecAuthenticationType));
require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_authenticationType_failed, status = errSecBufferTooSmall);
attrListPtr->attr[attrListPtr->count].tag = kSecAuthenticationTypeItemAttr;
attrListPtr->attr[attrListPtr->count].length = sizeof(SecAuthenticationType);
*(SecAuthenticationType *)(attrListPtr->attr[attrListPtr->count].data) = _SecAuthenticationTypeForSecAttrAuthenticationType(value);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrComment, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecCommentItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrDescription, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecDescriptionItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrLabel, (const void **)&value) ) {
status = _CFStringCreateAttribute((CFStringRef)value, kSecLabelItemAttr, &attrListPtr->attr[attrListPtr->count]);
require_noerr_quiet(status, CFStringCreateAttribute_failed);
++attrListPtr->count;
}
*attrList = attrListPtr;
return ( noErr );
malloc_authenticationType_failed:
malloc_protocol_failed:
malloc_port_failed:
CFStringCreateAttribute_failed:
malloc_attrPtr_failed:
_FreeAttrList(attrListPtr);
calloc_attrListPtr_failed:
return ( errSecBufferTooSmall );
}
static CFStringRef
_AppNameFromSecTrustedApplication(
CFAllocatorRef alloc,
SecTrustedApplicationRef appRef)
{
CFStringRef result;
OSStatus status;
CFDataRef appDataRef;
result = NULL;
status = SecTrustedApplicationCopyData(appRef, &appDataRef);
if ( status == noErr ) {
CFStringRef path;
path = CFStringCreateWithCString(NULL, (char *)CFDataGetBytePtrVoid(appDataRef), kCFStringEncodingUTF8);
if ( path != NULL ) {
if ( CFStringHasPrefix(path, CFSTR("/")) && (CFStringFind(path, CFSTR("://"), 0).location == kCFNotFound) ) {
CFRange nameRange, compRg;
nameRange = CFRangeMake(0, CFStringGetLength(path));
while ( (nameRange.length > 0) && (CFStringGetCharacterAtIndex(path, nameRange.length - 1) == '/') ) {
nameRange.length --;
}
if ( nameRange.length > 0 ) {
if ( CFStringFindWithOptions(path, CFSTR("/"), nameRange, kCFCompareBackwards, &compRg) ) {
nameRange.length = nameRange.location + nameRange.length - (compRg.location + 1);
nameRange.location = compRg.location + 1;
}
result = CFStringCreateWithSubstring(alloc, path, nameRange);
}
}
CFRelease(path);
}
CFRelease(appDataRef);
}
return ( result );
}
static OSStatus
_SafeSecKeychainItemDelete(
SecKeychainItemRef itemRef)
{
OSStatus status;
SecAccessRef access;
CFArrayRef aclList;
SecACLRef acl;
CFArrayRef appList;
CFStringRef description;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
status = SecKeychainItemCopyAccess(itemRef, &access);
require_noerr(status, SecKeychainItemCopyAccessFailed);
status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
require_noerr(status, SecAccessCopySelectedACLListFailed);
require_quiet(aclList != NULL, noACLList);
acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
require_quiet(acl != NULL, noACL);
status = SecACLCopySimpleContents(acl, &appList, &description, &promptSelector);
require_noerr(status, SecACLCopySimpleContentsFailed);
require_quiet(appList != NULL, noAppList);
if ( CFArrayGetCount(appList) == 1 ) {
SecTrustedApplicationRef itemAppRef, currentAppRef;
CFStringRef itemAppName, currentAppName;
itemAppRef = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(appList, 0);
require(itemAppRef != NULL, noItemAppRef);
itemAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), itemAppRef);
require(itemAppName != NULL, noAppName);
status = SecTrustedApplicationCreateFromPath(NULL, ¤tAppRef);
require((status == noErr) && (currentAppRef != NULL), SecTrustedApplicationCreateFromPathFailed);
currentAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), currentAppRef);
require(currentAppName != NULL, noCurrentAppName);
if ( CFStringCompare(currentAppName, itemAppName, 0) == kCFCompareEqualTo ) {
SecKeychainItemDelete(itemRef);
}
CFRelease(currentAppName);
noCurrentAppName:
CFRelease(currentAppRef);
SecTrustedApplicationCreateFromPathFailed:
CFRelease(itemAppName);
noAppName:
noItemAppRef:
;
}
if ( description ) {
CFRelease(description);
}
CFRelease(appList);
noAppList:
SecACLCopySimpleContentsFailed:
noACL:
CFRelease(aclList);
noACLList:
SecAccessCopySelectedACLListFailed:
CFRelease(access);
SecKeychainItemCopyAccessFailed:
return ( status );
}
#pragma mark SecItem API functions
OSStatus
SecItemCopyMatching(
CFDictionaryRef query,
CFTypeRef *result)
{
OSStatus status;
Boolean returningAttributes, returnAllMatches;
CFAllocatorRef allocator;
SecKeychainAttributeList *attrList;
SecKeychainSearchRef search;
SecKeychainItemRef item;
CFTypeRef value;
*result = NULL;
allocator = CFGetAllocator(query);
require_action(CFDictionaryGetValueIfPresent(query, kSecClass, (const void **)&value) &&
CFEqual(kSecClassInternetPassword, value), NotInternetPasswordClass, status = errSecItemClassMissing);
returningAttributes = CFDictionaryGetValueIfPresent(query, kSecReturnAttributes, (const void **)&value) && CFEqual(kCFBooleanTrue, value);
if ( !returningAttributes ) {
require_action(CFDictionaryGetValueIfPresent(query, kSecReturnData, (const void **)&value) &&
CFEqual(kCFBooleanTrue, value), UnsupportedResultType, status = errSecReturnRefUnsupported);
}
returnAllMatches = CFDictionaryGetValueIfPresent(query, kSecMatchLimit, (const void **)&value) && CFEqual(kSecMatchLimitAll, value);
if ( returnAllMatches ) {
require_action(returningAttributes, UnsupportedResultTypeForAllMatches, status = errSecReturnDataUnsupported);
}
status = _CreateSecKeychainAttributeListFromDictionary(query, &attrList);
require_noerr(status, CreateAttributeListFromDictionary_failed);
status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, (attrList->count == 0) ? NULL : attrList, &search);
require_noerr(status, SecKeychainSearchCreateFromAttributes_failed);
if ( !returnAllMatches ) {
status = SecKeychainSearchCopyNext(search, &item);
if ( status == noErr ) {
if ( !returningAttributes ) {
UInt32 length;
void *data;
status = SecKeychainItemCopyContent(item, NULL, NULL, &length, &data);
if ( status == noErr ) {
*result = CFDataCreate(allocator, (UInt8 *)data, length);
(void) SecKeychainItemFreeContent(NULL, data);
}
}
else { status = _CreateAttributesDictionaryFromItem(allocator, item, (CFDictionaryRef *)result);
}
CFRelease(item);
}
}
else {
CFMutableArrayRef mutableResult;
CFIndex matchCount;
mutableResult = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
require_action( mutableResult != NULL, CFArrayCreateMutable_failed, status = errSecBufferTooSmall);
while ( SecKeychainSearchCopyNext(search, &item) == noErr ) {
CFDictionaryRef dictionary;
status = _CreateAttributesDictionaryFromItem(allocator, item, &dictionary);
check_noerr(status);
CFArrayAppendValue(mutableResult, dictionary);
CFRelease(dictionary);
CFRelease(item);
}
matchCount = CFArrayGetCount(mutableResult);
if ( matchCount != 0 ) {
*result = CFArrayCreateCopy(allocator, mutableResult);
}
else {
status = errSecItemNotFound;
}
CFRelease(mutableResult);
}
CFArrayCreateMutable_failed:
CFRelease(search);
SecKeychainSearchCreateFromAttributes_failed:
_FreeAttrList(attrList);
CreateAttributeListFromDictionary_failed:
UnsupportedResultTypeForAllMatches:
UnsupportedResultType:
NotInternetPasswordClass:
return ( status );
}
OSStatus
SecItemCopyDisplayNames(
CFArrayRef items,
CFArrayRef *displayNames)
{
BEGIN_SECAPI
Required(items);
Required(displayNames);
return unimpErr;
END_SECAPI
}
OSStatus
SecItemAdd(
CFDictionaryRef attributes,
CFTypeRef *result)
{
OSStatus status;
SecKeychainAttributeList *attrList;
CFDataRef theData;
SecKeychainItemRef item;
CFTypeRef value;
require_action(CFDictionaryGetValueIfPresent(attributes, kSecClass, (const void **)&value) &&
CFEqual(kSecClassInternetPassword, value), NotInternetPasswordClass, status = errSecItemClassMissing);
require_action(result == NULL || CFDictionaryGetValueIfPresent(attributes, kSecReturnAttributes, (const void **)&value) && CFEqual(kCFBooleanTrue, value), UnsupportedResultType, status = errSecReturnDataUnsupported);
status = _CreateSecKeychainAttributeListFromDictionary(attributes, &attrList);
require_noerr(status, CreateAttributeListFromDictionary_failed);
theData = (CFDataRef)CFDictionaryGetValue(attributes, kSecValueData);
require_action(theData != NULL, CFDictionaryGetValue_failed, status = errSecUnsupportedOperation);
status = SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass, attrList, CFDataGetLength(theData), CFDataGetBytePtrVoid(theData), NULL, NULL, &item);
require_noerr(status, SecKeychainItemCreateFromContent_failed);
if ( result != NULL ) {
status = _CreateAttributesDictionaryFromItem(CFGetAllocator(attributes), item, (CFDictionaryRef *)result);
check_noerr(status);
}
CFRelease(item);
SecKeychainItemCreateFromContent_failed:
CFDictionaryGetValue_failed:
_FreeAttrList(attrList);
CreateAttributeListFromDictionary_failed:
UnsupportedResultType:
NotInternetPasswordClass:
return ( status );
}
OSStatus
SecItemUpdate(
CFDictionaryRef query,
CFDictionaryRef attributesToUpdate)
{
OSStatus status;
SecKeychainAttributeList *attrList;
SecKeychainSearchRef search;
SecKeychainItemRef item;
CFTypeRef value;
SecKeychainAttributeList *changeAttrList;
CFDataRef theData;
Boolean itemFound;
require_action(CFDictionaryGetValueIfPresent(query, kSecClass, (const void **)&value) &&
CFEqual(kSecClassInternetPassword, value), NotInternetPasswordClass, status = errSecItemClassMissing);
status = _CreateSecKeychainAttributeListFromDictionary(query, &attrList);
require_noerr(status, CreateAttributeListFromDictionary_failed);
status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, (attrList->count == 0) ? NULL : attrList, &search);
require_noerr(status, SecKeychainSearchCreateFromAttributes_failed);
status = _CreateSecKeychainAttributeListFromDictionary(attributesToUpdate, &changeAttrList);
require_noerr(status, CreateAttributeListFromDictionary_changeAttrList_failed);
theData = (CFDataRef)CFDictionaryGetValue(attributesToUpdate, kSecValueData);
itemFound = FALSE;
while ( SecKeychainSearchCopyNext(search, &item) == noErr ) {
itemFound = TRUE;
status = SecKeychainItemModifyContent(item, (changeAttrList->count == 0) ? NULL : changeAttrList,
(theData != NULL) ? CFDataGetLength(theData) : 0, (theData != NULL) ? CFDataGetBytePtrVoid(theData) : NULL);
check_noerr(status);
CFRelease(item);
}
if ( !itemFound ) {
status = errSecItemNotFound;
}
_FreeAttrList(changeAttrList);
CreateAttributeListFromDictionary_changeAttrList_failed:
CFRelease(search);
SecKeychainSearchCreateFromAttributes_failed:
_FreeAttrList(attrList);
CreateAttributeListFromDictionary_failed:
NotInternetPasswordClass:
return ( status );
}
OSStatus
SecItemDelete(
CFDictionaryRef query)
{
OSStatus status;
SecKeychainAttributeList *attrList;
SecKeychainSearchRef search;
SecKeychainItemRef item;
CFTypeRef value;
Boolean itemFound;
require_action(CFDictionaryGetValueIfPresent(query, kSecClass, (const void **)&value) &&
CFEqual(kSecClassInternetPassword, value), NotInternetPasswordClass, status = errSecItemClassMissing);
status = _CreateSecKeychainAttributeListFromDictionary(query, &attrList);
require_noerr(status, CreateAttributeListFromDictionary_failed);
status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, (attrList->count == 0) ? NULL : attrList, &search);
require_noerr(status, SecKeychainSearchCreateFromAttributes_failed);
itemFound = FALSE;
while ( SecKeychainSearchCopyNext(search, &item) == noErr ) {
itemFound = TRUE;
status = _SafeSecKeychainItemDelete(item);
check_noerr(status);
CFRelease(item);
}
if ( !itemFound ) {
status = errSecItemNotFound;
}
CFRelease(search);
SecKeychainSearchCreateFromAttributes_failed:
_FreeAttrList(attrList);
CreateAttributeListFromDictionary_failed:
NotInternetPasswordClass:
return ( status );
}