我们有一个启动守护程序(必然由于各种原因)以root身份运行,并通过网络与服务器组件通信。它需要对服务进行身份验证,因此在首次获取密码时,我们会将其保存到系统密钥链中。在随后的发布中,我们的想法是从钥匙串中检索密码并使用它来验证网络服务。
这一直运行良好,但在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
。
我们已经检查了一些其他细节以及我们尝试过的事情,但无济于事:
SecKeychainAddInternetPassword
的参数,但这似乎没有任何区别。SecKeychainUnlock()
明确解锁钥匙串,但正如文档所示,这似乎是多余的。Keychain Access.app
中的项目会导致SecKeychainFindInternetPassword()
产生errSecItemNotFound
。{li>所以它绝对可以找到已保存的项目,但它不允许阅读。钥匙串文档并不易于阅读,而且部分内容相当重复。 ("为了做Y,你需要做Y,"没有提到你为什么要做Y.)尽管如此,我想我已经完成并理解了大部分。我们特定设置的各个方面都没有详细介绍(从守护程序访问),但似乎很清楚,访问以前由同一个应用程序保存的项目不需要任何特殊授权或认证。这与我们所看到的行为直接矛盾。
有什么想法吗?
答案 0 :(得分:8)
在这几天花了几个小时后,我们终于弄明白了发生了什么。
首先,我尝试构建一个可以重现问题的最小示例。 这并没有因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/
显然,它会就地覆盖文件而不是创建新的vnode,编写该文件,然后将其重命名为旧文件。所以解决方案是首先cp
到临时目录,然后mv
到位。或者在使用cp
之前删除目标文件。
我一做到这一点就行了!