(必然的に、さまざまな理由から) root として実行され、ネットワーク経由でサーバー コンポーネントと通信する Launch Daemon があります。サービスで認証する必要があるため、最初にパスワードを取得するときに、それをシステム キーチェーンに保存します。その後の起動では、キーチェーンからパスワードを取得し、それを使用してネットワーク サービスで認証するという考え方です。
これは問題なく機能していましたが、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 証明書で署名されています。
- デーモン バイナリには、バンドル ID とバージョンを含む Info.plist セクションが埋め込まれています。
- Keychain Access.app のパスワード項目の [アクセス制御] タブにある [これらのアプリケーションによるアクセスを常に許可する] リストにデーモン バイナリが表示されます。
- キーチェーンアクセスで「すべてのアプリケーションがこのアイテムにアクセスできるようにする」に手動で切り替えると、機能します。ただし、これは、パスワードをキーチェーンに保存するという点をやや無効にします。
- パラメータを に変更してみ
SecKeychainAddInternetPassword
ましたが、違いはないようです。 - でキーチェーンを明示的にロック解除しようとしまし
SecKeychainUnlock()
たが、ドキュメントが示唆するように、これは不必要なようです。 - ご想像のとおり、アイテムを削除すると yieldが
Keychain Access.app
発生します。したがって、保存されたアイテムを確実に見つけることができますが、それを読み取ることは許可されていません。SecKeychainFindInternetPassword()
errSecItemNotFound
キーチェーンのドキュメントは正確に読むのは簡単ではなく、部分的にはトートロジー的です。(「Y を行うには、Y を行う必要があります」と、Y を実行する理由については言及しません。) それでも、私はそれをやり遂げ、そのほとんどを理解したと思います。特定のセットアップのさまざまな側面 (デーモンからのアクセス) については詳しく説明していませんが、同じアプリによって以前に保存されたアイテムへのアクセスには、特別な承認や認証が必要ないことは明らかです。これは、私たちが見ている動作とは正反対です。
何か案は?