We have Launch Daemon, which (necessarily, for various reasons) works as root and which communicates with the server component through the network. It must authenticate with the service, so when it first receives the password, we store it in the system keychain. In subsequent launches, the idea is to extract the password from the key fob and use it for authentication using the network service.
This works fine, but on macOS 10.12 the existing code stops working, and we completely stopped on how to fix it. It comes down to the following:
Regardless of whether we save the new password or retrieve the old one, we get a link to the system keychain using this:
SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &system_keychain);
We have also disabled user interaction for a good measure, although we expect it to already disconnect in the context of the daemon.
SecKeychainSetUserInteractionAllowed(false);
When saving a new password in the keychain, we use
OSStatus status = SecKeychainAddInternetPassword( system_keychain, urlLength, server_base_url, 0, NULL, usernameLength, username, 0, NULL, 0, kSecProtocolTypeAny, kSecAuthenticationTypeAny, passwordLength, password, NULL);
It works a lot. Success is reported, and I see an element in the "system" keychain in Keychain Access.app.
Retrieving it in subsequent runs of our daemon is performed using this line:
status = SecKeychainFindInternetPassword( system_keychain, urlLength, url, 0, NULL, usernameLength, username, 0, NULL, 0, kSecProtocolTypeAny, kSecAuthenticationTypeAny, &passwordLength, &password_data, NULL);
Unfortunately, this began to return errSecAuthFailed for reasons we errSecAuthFailed not understand.
A few additional data that we checked, and all that we tried, to no avail:
- The daemon daemon file is signed with a developer identifier certificate.
- The daemon file contains the built-in Info.plist section with the identifier and version of the package.
- I see the daemon binary in the Always allow access by these applications list on the Access Control tab of the password item in Keychain Access.app.
- If I manually switch to "Allow all applications access to this item" in Keychain Access, it works. However, this somewhat degrades the password storage point in the keychain.
- We tried playing with the
SecKeychainAddInternetPassword parameters, but that didn't seem to make any difference. - We tried to explicitly unlock the keychain using
SecKeychainUnlock() , but, as the documentation suggests, this seems redundant. - Removing an item in
Keychain Access.app causes SecKeychainFindInternetPassword() give errSecItemNotFound , as you would expect. That way, he can definitely find the saved item, he is simply not allowed to read it.
The keychain documentation is not so easy to read, but rather tautological in parts. ("To make Y, you need to make Y," without mentioning why you want to make Y.) However, I think I managed and understood most of this. Various aspects of our specific settings are not considered in detail (access from the daemon), but it seems pretty obvious that access to an element previously stored in the same application does not require special authorization or authentication. This directly contradicts the behavior that we observe.
Any ideas?