EXC_BAD_ACCESS 尝试访问 OS X 钥匙串时
EXC_BAD_ACCESS While trying to access OS X Keychain
我写了一个示例代码(之前收到 )来从 OS X 钥匙串中添加和检索密码。我能够成功添加密码,但是当我尝试检索它时,我得到一个 EXC_BAD_ACCESS (code=EXC_I386_GPFLT)。我尝试了两种方式:
- 使用 SecItemCopyMatching API,它使用基于查询的方法来访问钥匙串。
- 使用 SecKeychainFindGenericPassword。
BAD ACCESS 错误仅在第一种方法中发生,第二种方法成功。我正在尝试使用第一种方法,以便我可以确保在完成后使用 SecKeychainItemFreeContent 进行清理。
注意 - 这是示例代码,因此我没有对 return 值进行任何检查。尽管我一直在调试器中关注它们,但没有发现任何错误。
#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;
}
您似乎向 SecKeychainItemCopyAttributesAndData
传递了错误的参数。
在您的查询字典中,您指定了三种不同的 return 类型:kSecReturnAttributes
、kSecReturnData
和 kSecReturnRef
。 SecItemCopyMatching
的文档是这样说的:
Use the keys found in Item Return Result Keys to indicate whether you seek the item’s attributes, the item’s data, a reference to the data, a persistent reference to the data, or a combination of these. When you specify more than one return type, the search returns a dictionary containing each of the types you request. When your search allows multiple results, they’re all returned together in an array of items.
因此,由 SecItemCopyMatching
编辑的 return 类型(因为您限制为一个结果)将是 CFDictionary
包含项目数据、项目属性和对项目的引用.
然后您将它传递给 SecKeychainItemCopyAttributesAndData
,但是第一个参数的文档说:
itemRef
A reference to the keychain item from which you wish to retrieve data or attributes.
如果您将查询字典修改为仅包含 kSecReturnRef
return 类型(删除 kSecReturnAttributes
和 kSecReturnData
),您的代码将起作用。
(或者,从字典中提取 SecItemCopyMatching
是 returning 的引用,并将 that 传递给 SecKeychainItemCopyAttributesAndData
)
我写了一个示例代码(之前收到
- 使用 SecItemCopyMatching API,它使用基于查询的方法来访问钥匙串。
- 使用 SecKeychainFindGenericPassword。
BAD ACCESS 错误仅在第一种方法中发生,第二种方法成功。我正在尝试使用第一种方法,以便我可以确保在完成后使用 SecKeychainItemFreeContent 进行清理。
注意 - 这是示例代码,因此我没有对 return 值进行任何检查。尽管我一直在调试器中关注它们,但没有发现任何错误。
#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;
}
您似乎向 SecKeychainItemCopyAttributesAndData
传递了错误的参数。
在您的查询字典中,您指定了三种不同的 return 类型:kSecReturnAttributes
、kSecReturnData
和 kSecReturnRef
。 SecItemCopyMatching
的文档是这样说的:
Use the keys found in Item Return Result Keys to indicate whether you seek the item’s attributes, the item’s data, a reference to the data, a persistent reference to the data, or a combination of these. When you specify more than one return type, the search returns a dictionary containing each of the types you request. When your search allows multiple results, they’re all returned together in an array of items.
因此,由 SecItemCopyMatching
编辑的 return 类型(因为您限制为一个结果)将是 CFDictionary
包含项目数据、项目属性和对项目的引用.
然后您将它传递给 SecKeychainItemCopyAttributesAndData
,但是第一个参数的文档说:
itemRef
A reference to the keychain item from which you wish to retrieve data or attributes.
如果您将查询字典修改为仅包含 kSecReturnRef
return 类型(删除 kSecReturnAttributes
和 kSecReturnData
),您的代码将起作用。
(或者,从字典中提取 SecItemCopyMatching
是 returning 的引用,并将 that 传递给 SecKeychainItemCopyAttributesAndData
)