我写了一个示例代码(前面收到了help),用于从OS X钥匙串添加和检索密码。我能够成功添加密码,但是当我尝试检索密码时,我得到一个EXC_BAD_ACCESS(code = EXC_I386_GPFLT)。我尝试过两种方式:
BAD ACCESS错误仅在第一种方法中发生,第二种方法成功。我正在尝试使用第一种方法,以便确保完成后可以使用 SecKeychainItemFreeContent 进行清理。
注意-这是示例代码,因此我没有对返回值进行任何检查。尽管我一直在调试器中关注它们,但在此看不到任何错误。
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
int main(int argc, const char * argv[])
{
char acc_name[20];
char password[20];
CFStringRef keys[3];
printf("Enter account name - ");
scanf("%s", acc_name);
printf("\nEnter password - ");
scanf("%s", password);
keys[0] = kSecClass;
keys[1] = kSecAttrAccount;
keys[2] = kSecValueData;
CFTypeRef values[3];
values[0] = kSecClassGenericPassword;
values[1] = CFStringCreateWithCString(kCFAllocatorDefault, acc_name, kCFStringEncodingUTF8);
values[2] = CFStringCreateWithCString(kCFAllocatorDefault, password, kCFStringEncodingUTF8);
CFDictionaryRef query;
query = CFDictionaryCreate(kCFAllocatorDefault, (const void**) keys, (const void**) values, 3, NULL, NULL);
OSStatus result = SecItemAdd(query, NULL);
printf("%d\n", result);
printf("Retrieve\n");
SecKeychainItemRef pitem = NULL;
SecKeychainItemRef kch_ref = NULL;
CFStringRef qkeys[6];
qkeys[0] = kSecClass;
qkeys[1] = kSecAttrAccount;
qkeys[2] = kSecMatchLimit;
qkeys[3] = kSecReturnAttributes;
qkeys[4] = kSecReturnData;
qkeys[5] = kSecReturnRef;
CFTypeRef qvalues[6];
qvalues[0] = kSecClassGenericPassword;
qvalues[1] = CFStringCreateWithCString(kCFAllocatorDefault, acc_name, kCFStringEncodingUTF8);
qvalues[2] = kSecMatchLimitOne;
qvalues[3] = kCFBooleanTrue;
qvalues[4] = kCFBooleanTrue;
qvalues[5] = kCFBooleanTrue;
unsigned int plength = 0;
char *pdata = NULL;
unsigned int plength2 = 0;
void *pdata2 = NULL;
CFDictionaryRef extract_query = CFDictionaryCreate(kCFAllocatorDefault, (const void **)qkeys, (const void **)qvalues, 6, NULL, NULL);
result = SecItemCopyMatching(extract_query, (CFTypeRef *)&kch_ref);
SecKeychainItemCopyAttributesAndData(kch_ref, NULL, NULL, NULL, &plength2, &pdata2); // <-- EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
//result = SecKeychainFindGenericPassword(NULL, 0, NULL, (uint32)strlen(acc_name), acc_name, &plength, (void **)&pdata, &pitem);
if (result)
{
//return error;
}
printf("password - %s\n", pdata);
return 0;
}
答案 0 :(得分:0)
您似乎在向SecKeychainItemCopyAttributesAndData
传递了错误的参数。
在查询字典中,您指定三种不同的返回类型:kSecReturnAttributes
,kSecReturnData
和kSecReturnRef
。 SecItemCopyMatching
的文档中说:
使用“项目返回结果键”中的键来指示您是否要查找项目的属性,项目的数据,对数据的引用,对数据的持久引用或它们的组合。当您指定多个返回类型时,搜索将返回一个字典,其中包含您请求的每种类型。当您的搜索允许多个结果时,它们会以一系列项目一起返回。
因此,SecItemCopyMatching
返回的类型(因为您限制为一个结果)将是一个CFDictionary
,其中包含项目数据,项目属性和对该项目的引用。
然后将其传递给SecKeychainItemCopyAttributesAndData
,但是第一个参数的文档中说:
itemRef
对您希望从中检索数据或属性的钥匙串项目的引用。
如果您修改查询字典以仅包含kSecReturnRef
返回类型(删除kSecReturnAttributes
和kSecReturnData
),您的代码将起作用。
(或从SecItemCopyMatching
返回的字典中提取引用,并将 that 传递给SecKeychainItemCopyAttributesAndData
)