[vlc-commits] keychain: add support for iOS and tvOS

Felix Paul Kühne git at videolan.org
Sun Apr 22 20:20:03 CEST 2018


vlc | branch: master | Felix Paul Kühne <felix at feepk.net> | Sun Apr 22 12:47:50 2018 +0200| [c628ce8f794ca9f1de846f90c6011267990f1859] | committer: Felix Paul Kühne

keychain: add support for iOS and tvOS

To achieve this, Find and Remove were re-written without a functional change for macOS

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c628ce8f794ca9f1de846f90c6011267990f1859
---

 modules/keystore/Makefile.am |   2 +-
 modules/keystore/keychain.m  | 120 +++++++++++++++++++------------------------
 2 files changed, 53 insertions(+), 69 deletions(-)

diff --git a/modules/keystore/Makefile.am b/modules/keystore/Makefile.am
index a1b414949e..9d5e5bcc78 100644
--- a/modules/keystore/Makefile.am
+++ b/modules/keystore/Makefile.am
@@ -30,7 +30,7 @@ libkeychain_plugin_la_SOURCES = keystore/keychain.m keystore/list_util.c keystor
 libkeychain_plugin_la_OBJCFLAGS = $(AM_OBJCFLAGS) -fobjc-arc
 libkeychain_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(keystoredir)' -Wl,-framework,Foundation -Wl,-framework,Security -Wl,-framework,Cocoa
 
-if HAVE_OSX
+if HAVE_DARWIN
 keystore_LTLIBRARIES += libkeychain_plugin.la
 endif
 
diff --git a/modules/keystore/keychain.m b/modules/keystore/keychain.m
index 09b2dc9c1c..8eec53ba09 100644
--- a/modules/keystore/keychain.m
+++ b/modules/keystore/keychain.m
@@ -30,7 +30,16 @@
 
 #include "list_util.h"
 
-#import <Cocoa/Cocoa.h>
+#include <TargetConditionals.h>
+
+#if TARGET_OS_IPHONE
+  #import <Foundation/Foundation.h>
+  #define OSX_MAVERICKS 1
+#else
+  #import <Cocoa/Cocoa.h>
+  #define OSX_MAVERICKS (NSAppKitVersionNumber >= 1265)
+#endif
+
 #import <Security/Security.h>
 
 static int Open(vlc_object_t *);
@@ -107,7 +116,7 @@ static const char *const accessibility_list_text[] = {
 
 vlc_module_begin()
     set_shortname(N_("Keychain keystore"))
-    set_description(N_("Keystore for iOS, Mac OS X and tvOS"))
+    set_description(N_("Keystore for iOS, macOS and tvOS"))
     set_category(CAT_ADVANCED)
     set_subcategory(SUBCAT_ADVANCED_MISC)
     add_integer("keychain-synchronize", 1, SYNC_ITEMS_TEXT, SYNC_ITEMS_LONGTEXT, true)
@@ -205,7 +214,6 @@ static NSString * ErrorForStatus(OSStatus status)
     return message;
 }
 
-#define OSX_MAVERICKS (NSAppKitVersionNumber >= 1265)
 extern const CFStringRef kSecAttrAccessible;
 
 #pragma clang diagnostic push
@@ -339,24 +347,24 @@ static unsigned int Find(vlc_keystore *p_keystore,
                          vlc_keystore_entry **pp_entries)
 {
     CFTypeRef result = NULL;
-
-    NSMutableDictionary *query = CreateQuery(p_keystore);
-    [query setObject:@(YES) forKey:(__bridge id)kSecReturnRef];
-    [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
+    NSMutableDictionary *baseLookupQuery = CreateQuery(p_keystore);
+    OSStatus status;
 
     /* set attributes */
-    SetAttributesForQuery(ppsz_values, query, NULL);
+    SetAttributesForQuery(ppsz_values, baseLookupQuery, NULL);
 
     /* search */
-    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
+    NSMutableDictionary *searchQuery = [baseLookupQuery mutableCopy];
+    [searchQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
+    [searchQuery setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
 
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)searchQuery, &result);
     if (status != errSecSuccess) {
         msg_Warn(p_keystore, "lookup failed (%i: '%s')", status, [ErrorForStatus(status) UTF8String]);
         return 0;
     }
 
     NSArray *listOfResults = (__bridge_transfer NSArray *)result;
-
     NSUInteger count = listOfResults.count;
     msg_Dbg(p_keystore, "found %lu result(s) for the provided attributes", count);
 
@@ -372,97 +380,73 @@ static unsigned int Find(vlc_keystore *p_keystore,
             return 0;
         }
 
-        SecKeychainItemRef itemRef = (__bridge SecKeychainItemRef)([listOfResults objectAtIndex:i]);
-
-        SecKeychainAttributeInfo attrInfo;
-        attrInfo.count = 1;
-        UInt32 tags[1] = {kSecAccountItemAttr}; //, kSecAccountItemAttr, kSecServerItemAttr, kSecPortItemAttr, kSecProtocolItemAttr, kSecPathItemAttr};
-        attrInfo.tag = tags;
-        attrInfo.format = NULL;
-
-        SecKeychainAttributeList *attrList = NULL;
-
-        UInt32 secretDataLength;
-        void * secretData;
-
-        status = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, &secretDataLength, &secretData);
+        NSDictionary *keychainItem = [listOfResults objectAtIndex:i];
+        NSString *accountName = [keychainItem objectForKey:(__bridge id)kSecAttrAccount];
+        NSMutableDictionary *passwordFetchQuery = [baseLookupQuery mutableCopy];
+        [passwordFetchQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
+        [passwordFetchQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
+        [passwordFetchQuery setObject:accountName forKey:(__bridge id)kSecAttrAccount];
 
+        CFTypeRef secretResult = NULL;
+        status = SecItemCopyMatching((__bridge CFDictionaryRef)passwordFetchQuery, &secretResult);
         if (status != noErr) {
             msg_Err(p_keystore, "Lookup error: %i (%s)", status, [ErrorForStatus(status) UTF8String]);
-            vlc_keystore_release_entries(p_entries, count);
+            vlc_keystore_release_entries(p_entries, (unsigned int)count);
             return 0;
         }
 
-        for (unsigned x = 0; x < attrList->count; x++) {
-            SecKeychainAttribute *attr = &attrList->attr[i];
-            switch (attr->tag) {
-                case kSecAccountItemAttr:
-                    if (!p_entry->ppsz_values[KEY_USER]) {
-                        msg_Dbg(p_keystore, "using account name from the keychain for login");
-
-                        char *paddedName = calloc(1, attr->length + 1);
-                        memcpy(paddedName, attr->data, attr->length);
-                        p_entry->ppsz_values[KEY_USER] = paddedName;
-                    }
-                    break;
-                default:
-                    break;
-            }
+        if (!p_entry->ppsz_values[KEY_USER]) {
+            msg_Dbg(p_keystore, "using account name from the keychain for login");
+            p_entry->ppsz_values[KEY_USER] = strdup([accountName UTF8String]);
         }
 
+        NSData *secretData = (__bridge_transfer NSData *)secretResult;
+        NSUInteger secretDataLength = secretData.length;
+
         /* we need to do some padding here, as string is expected to be 0 terminated */
         uint8_t *paddedSecretData = calloc(1, secretDataLength + 1);
-        memcpy(paddedSecretData, secretData, secretDataLength);
+        memcpy(paddedSecretData, secretData.bytes, secretDataLength);
         vlc_keystore_entry_set_secret(p_entry, paddedSecretData, secretDataLength + 1);
         free(paddedSecretData);
-
-        SecKeychainItemFreeAttributesAndData(attrList, secretData);
     }
 
     *pp_entries = p_entries;
 
-    return count;
+    return (unsigned int)count;
 }
 
 static unsigned int Remove(vlc_keystore *p_keystore,
                            const char *const ppsz_values[KEY_MAX])
 {
-    OSStatus status;
-
+    CFTypeRef result = NULL;
     NSMutableDictionary *query = CreateQuery(p_keystore);
+    OSStatus status;
 
     SetAttributesForQuery(ppsz_values, query, NULL);
 
-    CFTypeRef result = NULL;
-    [query setObject:@(YES) forKey:(__bridge id)kSecReturnRef];
+    [query setObject:@(YES) forKey:(__bridge id)kSecReturnAttributes];
     [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
 
-    BOOL failed = NO;
+    /* do a copy matching to see how many items we are going to delete */
     status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
+    if (status != errSecSuccess) {
+        msg_Warn(p_keystore, "lookup failed (%i: '%s')", status, [ErrorForStatus(status) UTF8String]);
+        return 0;
+    }
+
+    NSArray *listOfResults = (__bridge_transfer NSArray *)result;
+    NSUInteger count = listOfResults.count;
+    msg_Dbg(p_keystore, "found %lu result(s) for the provided attributes", count);
 
-    NSUInteger matchCount = 0;
+    /* delete everything!! */
+    status = SecItemDelete((__bridge CFDictionaryRef)query);
 
-    if (status == errSecSuccess) {
-        NSArray *matches = (__bridge_transfer NSArray *)result;
-        matchCount = matches.count;
-        msg_Dbg(p_keystore, "Found %lu match(es) for deletion", matchCount);
-
-        for (NSUInteger x = 0; x < matchCount; x++) {
-            status = SecKeychainItemDelete((__bridge SecKeychainItemRef _Nonnull)([matches objectAtIndex:x]));
-            if (status != noErr) {
-                msg_Err(p_keystore, "Deletion error %i (%s)", status , [ErrorForStatus(status) UTF8String]);
-                failed = YES;
-            }
-        }
-    } else {
-        msg_Err(p_keystore, "Lookup error for deletion %i (%s)", status, [ErrorForStatus(status) UTF8String]);
+    if (status != errSecSuccess) {
+        msg_Err(p_keystore, "deleting items matching the provided attributes failed");
         return VLC_EGENERIC;
     }
 
-    if (failed)
-        return VLC_EGENERIC;
-
-    return matchCount;
+    return (unsigned int)count;
 }
 
 static int Open(vlc_object_t *p_this)



More information about the vlc-commits mailing list