2012-12-09 45 views
1

我想使用鑰匙串從我的Mac OSX應用程序存儲SMTP數據。我讀了Apple的Keychain服務編程指南並編寫了這種方法來存儲數據:SecKeychain加載項目

- (BOOL)saveSMPTData 
{ 
    OSStatus err; 
    SecKeychainItemRef item = nil; 
    SecProtocolType protocol = kSecProtocolTypeSMTP; 
    const char *accessLabelUTF8 = [KEYCHAIN_NAME UTF8String]; 
    const char *serverNameUTF8 = [self.serverName UTF8String]; 
    const char *usernameUTF8 = [self.username UTF8String]; 
    const char *passwordUTF8 = [self.password UTF8String]; 

    SecAccessRef access = createAccess(KEYCHAIN_NAME); 

    SecKeychainAttribute attrs[] = { 
     { kSecLabelItemAttr, (int)strlen(accessLabelUTF8), (char *)accessLabelUTF8 }, 
     { kSecAccountItemAttr, (int)strlen(usernameUTF8), (char *)usernameUTF8 }, 
     { kSecServerItemAttr, (int)strlen(serverNameUTF8), (char *)serverNameUTF8 }, 
     { kSecProtocolItemAttr, sizeof(SecProtocolType), (SecProtocolType *)&protocol } 
    }; 
    SecKeychainAttributeList attributes = { sizeof(attrs)/sizeof(attrs[0]), attrs }; 
    err = SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass, 
              &attributes, 
              (int)strlen(passwordUTF8), 
              passwordUTF8, 
              NULL, 
              access, 
              &item); 
    if (access) CFRelease(access); 
    if (item) CFRelease(item); 
    return (err == noErr); 
} 

SecAccessRef createAccess(NSString *accessLabel) 
{ 
    OSStatus err; 
    SecAccessRef access = nil; 
    NSArray *trustedApplications = nil; 

    SecTrustedApplicationRef myself; 
    err = SecTrustedApplicationCreateFromPath(NULL, &myself); 

    trustedApplications = [NSArray arrayWithObjects:(__bridge id)myself, nil]; 
    err = SecAccessCreate((__bridge CFStringRef)accessLabel, 
          (__bridge CFArrayRef)trustedApplications, &access); 

    if (err) return nil; 
    return access; 
} 

當然我也想加載它們。我的第一次嘗試是這樣的:

- (BOOL)loadDataFromKeychain 
{ 
    uint32_t serverNameLength = 0; 
    const char *serverName = NULL; 

    uint32_t usernameLength = 0; 
    const char *username = NULL; 

    uint32_t passwordLength = 0; 
    void **password = NULL; 

    OSStatus err = SecKeychainFindInternetPassword(NULL, 
                serverNameLength, serverName, 
                0, NULL, 
                usernameLength, username, 
                0, NULL, 
                0, 0, 
                0, 
                &passwordLength, password, 
                NULL); // How do I get the ItemRef? 

    return (err == noErr); 
} 

但這不起作用,我想我知道爲什麼不。我不知道如何獲得SecKeychainItemRefSecKeychainFindInternetPassword方法。

也許任何人都可以幫助我?

回答

2

而不是聲明password a void **,聲明它爲void *並通過&password爲倒數第二個參數。

您可能不需要SecKeychainItemRef來完成您要完成的任務。

順便說一下,你有沒有試過使用鑰匙串訪問來驗證項目正在進入鑰匙串?

+0

這也適用於'serverName'和'userName'。 (這也是提問者如果真的需要的話可以得到item ref:聲明一個變量來保存它,然後傳遞一個指針給變量。) –

+0

謝謝你的回答!按照您描述的方式聲明密碼來解決問題。但是我仍然不知道如何獲得物品參考。創建它後我無法將它保存在指針中,因爲我在重新啓動應用程序時只想讀出該項目。那麼,我如何搜索正確的項目? – kober

+0

@kober:使用'SecKeychainFindInternetPassword'並讓它返回給你,就像你已經用'SecKeychainItemCreateFromContent'做的那樣。 –