EXC_BAD_ACCESS尝试访问OS X钥匙串时

问题描述 投票:0回答:1

我写了一个示例代码(前面收到了help)来添加和检索来自OS X钥匙串的密码。我能够成功添加密码,但是当我尝试检索它时,我得到一个EXC_BAD_ACCESS(code = EXC_I386_GPFLT)。我尝试过两种方式:

  1. 使用SecItemCopyMatching API,该API使用基于查询的方法来访问钥匙串。
  2. 使用SecKeychainFindGenericPassword。

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;
}
c xcode macos security keychain
1个回答
0
投票
在查询字典中,您指定三种不同的返回类型:kSecReturnAttributeskSecReturnDatakSecReturnRefSecItemCopyMatching的文档说:

使用在“项目返回结果键”中找到的键来指示您是否要查找项目的属性,项目的数据,对数据的引用,对数据的持久引用或它们的组合。当您指定多个返回类型时,搜索将返回一个字典,其中包含您请求的每种类型。当您的搜索允许多个结果时,它们会以一系列项目一起返回。

因此,SecItemCopyMatching返回的类型(因为您限制为一个结果)将是CFDictionary,其中包含项目数据,项目属性和对该项目的引用。

然后将其传递给SecKeychainItemCopyAttributesAndData,但是第一个参数的文档说:

itemRef

对您希望从中检索数据或属性的钥匙串项目的引用。

如果您修改查询字典以仅包含kSecReturnRef返回类型(删除kSecReturnAttributeskSecReturnData,则您的代码将起作用。

(或从SecItemCopyMatching返回的字典中提取引用,并将

that

传递给SecKeychainItemCopyAttributesAndData
© www.soinside.com 2019 - 2024. All rights reserved.