isync's macOS keychain functionality interfaces with Apple's Security
framework via the SecKeychain API.  The SecItem API was introduced in
macOS 10.6 and became the preferred method using the keychain on macOS,
officially deprecating the SecKeychain API in macOS 10.10.  So the
codebase is currently using an API deprecated since 2014.

This can be seen by building isync on macOS.  Running `make` on macOS
26.4 with gcc 15.2.0 gives relevant compilation warnings:

        drv_imap.c: In function 'search_macos_keychain':
        drv_imap.c:2352:9: warning: 'SecKeychainFindInternetPassword' is 
deprecated: SecKeychain is deprecated [-Wdeprecated-declarations]
         2352 |         ret = SecKeychainFindInternetPassword(
              |         ^~~
        In file included from /.../SecImportExport.h:41,
                         from /.../Security.h:35,
                         from drv_imap.c:22:
        /.../SecKeychain.h:592:10: note: declared here
          592 | OSStatus SecKeychainFindInternetPassword(...)
              |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        drv_imap.c:2371:9: warning: 'SecKeychainItemFreeContent' is deprecated: 
SecKeychain is deprecated [-Wdeprecated-declarations]
         2371 |         SecKeychainItemFreeContent( NULL, password_data );
              |         ^~~~~~~~~~~~~~~~~~~~~~~~~~
        In file included from /.../Security.h:79:
        /.../SecKeychainItem.h:220:10: note: declared here
          220 | OSStatus SecKeychainItemFreeContent(...)
              |          ^~~~~~~~~~~~~~~~~~~~~~~~~~

Rewrite the search_macos_keychain() function to interface with the
SecItem API.  The function retains the same behaviour with regard to
the success or failure of searching the keychain.

The SecItem API requires the creation of multiple objects to specify the
search query, each of which may fail for whatever reason (most likely
OOM).  For now, use assertions to ensure no such object creation fails.
---
 src/drv_imap.c | 70 +++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 55 insertions(+), 15 deletions(-)

diff --git a/src/drv_imap.c b/src/drv_imap.c
index 410d6d616c50..ed3f7662caa4 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -2344,31 +2344,71 @@ ensure_user( imap_server_conf_t *srvc )
 static char *
 search_macos_keychain( const char *host, const char *user )
 {
-       void *password_data;
+       CFDictionaryRef query;
+       CFDataRef password_data;
+       const char *password_buffer;
        char *password_copy;
-       UInt32 password_length;
+       CFIndex password_length;
        OSStatus ret;
 
-       ret = SecKeychainFindInternetPassword(
-                       NULL,  // keychainOrArray
-                       strlen( host ), host,
-                       0, NULL,  // securityDomain
-                       strlen( user ), user,
-                       0, NULL,  // path
-                       0,  // port - we could use it, but it seems pointless
-                       kSecProtocolTypeIMAP,
-                       kSecAuthenticationTypeDefault,
-                       &password_length, &password_data,
-                       NULL );  // itemRef
+       CFStringRef account = CFStringCreateWithCString(
+               kCFAllocatorDefault, user, kCFStringEncodingUTF8 );
+       assert( account );
+
+       CFStringRef protocol = CFSTR( "imap" );
+       assert( protocol );
+
+       CFStringRef server = CFStringCreateWithCString(
+               kCFAllocatorDefault, host, kCFStringEncodingUTF8 );
+       assert( server );
+
+       /* Same index = key-value pair */
+       CFTypeRef query_keys[] = {
+               kSecClass,
+               kSecAttrAccount,
+               /* Also kSecAttrPort */
+               kSecAttrProtocol,
+               kSecAttrServer,
+               kSecReturnData
+       };
+       CFTypeRef query_vals[] = {
+               kSecClassInternetPassword,
+               account,
+               protocol,
+               server,
+               kCFBooleanTrue
+       };
+
+       static_assert( as(query_keys), "empty query" );
+       static_assert(
+               as(query_keys) == as(query_vals), "query size mismatch" );
+
+       query = CFDictionaryCreate(
+                       kCFAllocatorDefault,
+                       query_keys,
+                       query_vals,
+                       as(query_keys),
+                       &kCFTypeDictionaryKeyCallBacks,
+                       &kCFTypeDictionaryValueCallBacks );
+       assert( query );
+
+       ret = SecItemCopyMatching( query, (CFTypeRef *)&password_data );
+       CFRelease( query );
+       CFRelease( server );
+       CFRelease( protocol );
+       CFRelease( account );
        if (ret != errSecSuccess) {
                CFStringRef errmsg = SecCopyErrorMessageString( ret, NULL );
                error( "Looking up Keychain failed: %s\n",
                       CFStringGetCStringPtr( errmsg, kCFStringEncodingUTF8 ) );
                CFRelease( errmsg );
                return NULL;
        }
-       password_copy = nfstrndup( password_data, password_length );
-       SecKeychainItemFreeContent( NULL, password_data );
+
+       password_buffer = (const char *)CFDataGetBytePtr( password_data );
+       password_length = CFDataGetLength( password_data );
+       password_copy = nfstrndup( password_buffer, password_length );
+       CFRelease( password_data );
        return password_copy;
 }
 #endif /* HAVE_MACOS_KEYCHAIN */
-- 
2.50.1 (Apple Git-155)



_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to