2016-11-16 23 views
5

我們有一個啓動守護進程(由於各種原因)必須以root身份運行,並通過網絡與服務器組件進行通信。它需要使用服務進行身份驗證,所以當它第一次獲得密碼時,我們將它保存到系統鑰匙串中。在隨後的發佈中,想法是從鑰匙鏈中檢索密碼並使用它來與網絡服務進行認證。Mac啓動守護進程保存後無法從系統鑰匙串中檢索密碼

這一直工作正常,但在MacOS 10.12現有的代碼停止工作,我們已經完全難倒如何解決這個問題。它歸結爲:

無論我們節省了一個新的密碼或檢索一箇舊的,我們獲得對系統的鑰匙串基準來此:

SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &system_keychain); 

,因爲我們也禁止用戶交互好的措施,儘管我們預計它已經在守護進程中關閉了。

SecKeychainSetUserInteractionAllowed(false); 

當保存一個新的密碼到鑰匙鏈,我們使用

OSStatus status = SecKeychainAddInternetPassword(
    system_keychain, 
    urlLength, server_base_url, 
    0, NULL, 
    usernameLength, username, 
    0, NULL, 
    0, 
    kSecProtocolTypeAny, kSecAuthenticationTypeAny, 
    passwordLength, password, 
    NULL); 

該作品不多。報告成功後,我可以在Keychain Access.app的「系統」鑰匙串中看到該項目。

檢索其後續我們守護的運行與該行完成的:

status = SecKeychainFindInternetPassword(
    system_keychain, 
    urlLength, url, 
    0, NULL, 
    usernameLength, username, 
    0, NULL, 
    0, 
    kSecProtocolTypeAny, kSecAuthenticationTypeAny, 
    &passwordLength, &password_data, 
    NULL); 

不幸的是,這已經開始返回errSecAuthFailed對於那些我們不清楚原因。

我們嘗試,我們已經檢查了一些其他的細節和事情,都無濟於事:

  • 守護程序二進制與開發者ID證書籤名。
  • 守護程序二進制文件包含嵌入的Info.plist部分,其中包含一個包ID和版本。
  • 我可以在Keychain Access.app中的密碼項目的「訪問控制」選項卡的「始終允許訪問這些應用程序」列表中看到守護進程二進制文件。
  • 如果我手動切換到「允許所有應用程序訪問此項目」鑰匙串訪問,它的工作原理。然而,這有點破壞了在密鑰鏈中保存密碼的觀點。
  • 我們試過玩SecKeychainAddInternetPassword的參數,但這似乎沒有任何區別。
  • 我們試圖明確解鎖鑰匙扣SecKeychainUnlock(),但文檔建議,這似乎是多餘的。
  • 刪除項Keychain Access.app原因SecKeychainFindInternetPassword()產生errSecItemNotFound,正如你所期望。所以它絕對可以找到保存的項目,它只是不允許閱讀它。

鑰匙鏈文檔並不完全容易閱讀,而且部分文字是相當重複的。 (「爲了做Y,你需要做Y」,而沒有提及你爲什麼想要做Y.)然而,我認爲我已經完成並且理解了它的大部分內容。我們特定設置的各個方面並未詳細介紹(從守護進程訪問),但似乎很清楚,訪問之前由同一應用保存的項目不應該要求任何特殊授權或驗證。這與我們所看到的行爲直接相矛盾。

任何想法?

回答

7

幾天後,我們花了一些時間在這上面,最後我們研究了發生了什麼。

首先,我試圖建立一個最小的例子來重現問題。 這並沒有因errSecAuthFailed而失敗,因此沒有重現該問題。因此,回到原始的守護進程,必須有一些具體的事情出錯。

接下來的想法是在調用SecKeychainFindInternetPassword()時檢查系統日誌。這打開了一些錯誤消息:

securityd CSSM Exception: -2147411889 CSSMERR_CL_UNKNOWN_TAG 
securityd MacOS error: -67063 
securityd MacOS error: -67063 
securityd code requirement check failed (-67063), client is not Apple-signed 
securityd CSSM Exception: 32 CSSM_ERRCODE_OPERATION_AUTH_DENIED 
OurDaemon subsystem: com.apple.securityd, category: security_exception, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 2, enable_private_data: 0 
OurDaemon CSSM Exception: -2147416032 CSSMERR_CSP_OPERATION_AUTH_DENIED 

這表明該問題可能與代碼簽名。奇怪。用codesign -vv檢查二進制代碼簽名沒有返回任何問題。

在網絡上尋找錯誤消息的各個部分後,我發現-67063 corresponds to errSecCSGuestInvalid。評論的內容是「代碼身份已經失效」。

好吧,肯定有一些代碼錯誤,但是它是什麼意思,爲什麼會發生?

狩獵周圍的一些更終於變成了解釋,同時也解決方法:http://lists.apple.com/archives/apple-cdsa/2010/Mar/msg00027.html

這意味着,在某些時候,因爲節目開始了,一些 發生的情況,使得它無效。

如果您運行簽名程序

然後取代它(用,比方說,建設地方:-)一個 新版本,然後運行新版本,內核 仍將保留附加到可執行文件的vnode的舊簽名。 如果這是您的情況,只需刪除可執行文件並重新創建 即可清除問題,直至您再次覆蓋文件 :-)。我們建議您始終替換已簽名的代碼(mv(1),而不是 cp(1)或同等代碼)。

這解釋了它。我用

sudo cp path/to/built/daemon /usr/local/libexec/ 

顯然,這將覆蓋在原地的文件,而不是創建一個新的虛擬節點,編寫,然後重命名它覆蓋舊文件複製守護程序的新版本到位。所以解決方法是先將cp設置爲臨時目錄,然後再將mv設置到位。或者在使用cp之前刪除目標文件。

只要我這樣做,它的工作!