Revision: 27921
          http://sourceforge.net/p/bibdesk/svn/27921
Author:   hofman
Date:     2022-09-22 17:03:06 +0000 (Thu, 22 Sep 2022)
Log Message:
-----------
replace old keychain functions by core foundation based functions

Modified Paths:
--------------
    trunk/bibdesk/BDSKPasswordController.m

Modified: trunk/bibdesk/BDSKPasswordController.m
===================================================================
--- trunk/bibdesk/BDSKPasswordController.m      2022-09-21 09:11:45 UTC (rev 
27920)
+++ trunk/bibdesk/BDSKPasswordController.m      2022-09-22 17:03:06 UTC (rev 
27921)
@@ -47,111 +47,95 @@
 @synthesize passwordField, statusField;
 
 static inline void logError(NSString *action, OSStatus err) {
-    if (err != errSecItemNotFound && err != errSecUserCanceled)
+    if (err != noErr && err != errSecItemNotFound && err != errSecUserCanceled)
         NSLog(@"Error %d occurred %@ password: %@", (int)err, action, 
[(id)SecCopyErrorMessageString(err, NULL) autorelease]);
 }
 
-static inline SecKeychainAttributeList makeAttributeList(const char 
*serviceCString, const char *accountCString, const char *nameCString) {
-    // default is to use current user's username
-    if (accountCString == NULL)
-        accountCString = [NSUserName() UTF8String];
-    SecKeychainAttribute attrs[] = {
-        {kSecServiceItemAttr, (UInt32)strlen(serviceCString), (void 
*)serviceCString},
-        {kSecAccountItemAttr, (UInt32)strlen(accountCString), (void 
*)accountCString},
-        {kSecLabelItemAttr, (UInt32)strlen(nameCString), (void *)nameCString}};
-    SecKeychainAttributeList attributes = {3, attrs};
-    return attributes;
-}
-
 + (NSString *)passwordForKeychainService:(NSString *)service account:(NSString 
*)account name:(NSString *)name {
     // use the service name to get password from keychain and hash it with 
sha1 for comparison purposes
+    NSString *passwordString = nil;
+    NSData *passwordData = nil;
     OSStatus err;
+    NSMutableDictionary *query = [NSMutableDictionary dictionary];
     
-    const char *serviceCString = [service UTF8String];
-    const char *accountCString = [account UTF8String];
-    const char *nameCString = [name UTF8String];
-    void *password = NULL;
-    UInt32 passwordLength = 0;
-    NSString *passwordString = nil;
+    [query setObject:(NSString *)kSecClassGenericPassword forKey:(NSString 
*)kSecClass];
+    [query setObject:(NSString *)kSecMatchLimitOne forKey:(NSString 
*)kSecMatchLimit];
+    [query setObject:[NSNumber numberWithBool:YES] forKey:(NSString 
*)kSecReturnData];
+    [query setObject:service forKey:(NSString *)kSecAttrService];
+    if (account)
+        [query setObject:account forKey:(NSString *)kSecAttrAccount];
     
     // see if the password exists in the keychain
-    err = SecKeychainFindGenericPassword(NULL, strlen(serviceCString), 
serviceCString, account ? strlen(accountCString) : 0, accountCString, 
&passwordLength, &password, NULL);
+    err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef 
*)&passwordData);
     if (err == errSecItemNotFound && name) {
         // see if an item in the old format exists
-        SecKeychainItemRef itemRef = nil;
-        err = SecKeychainFindGenericPassword(NULL, strlen(nameCString), 
nameCString, 0, NULL, &passwordLength, &password, &itemRef);
+        [query setObject:name forKey:(NSString *)kSecAttrService];
+        [query removeObjectForKey:(NSString *)kSecAttrAccount];
+        err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef 
*)&passwordData);
         if (err == noErr) {
             // item in old format exists, update to new format
-            SecKeychainAttributeList attributes = 
makeAttributeList(serviceCString, accountCString, nameCString);
-            SecKeychainItemModifyAttributesAndData(itemRef, &attributes, 0, 
NULL);
-            CFRelease(itemRef);
+            NSDictionary *attributes = [NSDictionary 
dictionaryWithObjectsAndKeys:service, (NSString *)kSecAttrService, account ?: 
[NSUserName() dataUsingEncoding:NSUTF8StringEncoding], (NSString 
*)kSecAttrAccount, name, (NSString *)kSecAttrLabel, nil];
+            [query removeObjectForKey:(NSString *)kSecReturnData];
+            SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
         }
     }
+    
     if (err == noErr) {
-        passwordString = [[[NSString alloc] initWithBytes:password 
length:passwordLength encoding:NSUTF8StringEncoding] autorelease];
-        SecKeychainItemFreeContent(NULL, password);
+        passwordString = [[[NSString alloc] initWithData:passwordData 
encoding:NSUTF8StringEncoding] autorelease];
+        [passwordData release];
     } else {
         logError(@"getting", err);
     }
+    
     return passwordString;
 }
 
 + (BOOL)addOrModifyPassword:(NSString *)password forKeychainService:(NSString 
*)service account:(NSString *)account name:(NSString *)name {
+    NSString *passwordString = nil;
+    NSData *passwordData = nil;
+    OSStatus err;
+    NSMutableDictionary *query = [NSMutableDictionary dictionary];
+    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
     
-    NSParameterAssert(service != nil);
-    NSParameterAssert(password != nil);
-    const char *serviceCString = [service UTF8String];
-    const char *accountCString = [account UTF8String];
+    // first try to update an existing item
+    [query setObject:(NSString *)kSecClassGenericPassword forKey:(NSString 
*)kSecClass];
+    [query setObject:(NSString *)kSecMatchLimitOne forKey:(NSString 
*)kSecMatchLimit];
+    [query setObject:service forKey:(NSString *)kSecAttrService];
+    if (account)
+        [query setObject:account forKey:(NSString *)kSecAttrAccount];
     
-    OSStatus err;
-    SecKeychainItemRef itemRef = NULL;
-    const void *passwordData = [password UTF8String];
-    const void *oldPasswordData = NULL;
-    UInt32 passwordLength = 0;
+    [attributes setObject:[password dataUsingEncoding:NSUTF8StringEncoding] 
forKey:(NSString *)kSecValueData];
     
-    // first see if the password exists in the keychain
-    err = SecKeychainFindGenericPassword(NULL, strlen(serviceCString), 
serviceCString, account ? strlen(accountCString) : 0, accountCString, 
&passwordLength, (void **)&oldPasswordData, &itemRef);
+    err = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
     
-    if (err == noErr) {
-        // password was on keychain, so flush the buffer and then modify the 
keychain if necessary
-        if (passwordLength != strlen(passwordData) || strncmp(passwordData, 
oldPasswordData, passwordLength) != 0) {
-            err = SecKeychainItemModifyAttributesAndData(itemRef, NULL, 
strlen(passwordData), passwordData);
-            logError(@"modifying", err);
-        }
-        SecKeychainItemFreeContent(NULL, (void *)oldPasswordData);
-        CFRelease(itemRef);
-    } else if (err == errSecItemNotFound) {
-        // password not on keychain
+    logError(@"updating", err);
+    
+    if (err == errSecItemNotFound) {
+        [attributes setObject:service forKey:(NSString *)kSecAttrService];
+        [attributes setObject:account ?: [NSUserName() 
dataUsingEncoding:NSUTF8StringEncoding] forKey:(NSString *)kSecAttrAccount];
+        
         if (name) {
-            const char *nameCString = [name UTF8String];
-            
             // see if an item in the old format exists
-            err = SecKeychainFindGenericPassword(NULL, strlen(nameCString), 
nameCString, 0, NULL, NULL, NULL, &itemRef);
+            [attributes setObject:name forKey:(NSString *)kSecAttrLabel];
             
-            SecKeychainAttributeList attributes = 
makeAttributeList(serviceCString, accountCString, nameCString);
-            if (err == noErr) {
-                // password in old format was on keychain, modify the keychain 
to the new format
-                err = SecKeychainItemModifyAttributesAndData(itemRef, 
&attributes, strlen(passwordData), passwordData);
-                logError(@"modifying", err);
-                CFRelease(itemRef);
-            } else if (err == errSecItemNotFound) {
-                // password not on keychain, so add it
-                err = 
SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, 
strlen(passwordData), passwordData, NULL, NULL, NULL);
-                logError(@"adding", err);
-            } else {
-                logError(@"getting", err);
-            }
-        } else {
-            // simple password not on keychain, so add it
-            // default is to use current user's username
-            if (account == nil)
-                accountCString = [NSUserName() UTF8String];
-            err = SecKeychainAddGenericPassword(NULL, strlen(serviceCString), 
serviceCString, strlen(accountCString), accountCString, strlen(passwordData), 
passwordData, NULL);
+            [query setObject:name forKey:(NSString *)kSecAttrService];
+            [query removeObjectForKey:(NSString *)kSecAttrAccount];
+            
+            err = SecItemUpdate((CFDictionaryRef)query, 
(CFDictionaryRef)attributes);
+            
+            logError(@"updating", err);
+        }
+        
+        if (err == errSecItemNotFound) {
+            // password not yet on keychain, so add it
+            [attributes setObject:(NSString *)kSecClassGenericPassword 
forKey:(NSString *)kSecClass];
+            
+            err = SecItemAdd((CFDictionaryRef)attributes, NULL);
+            
             logError(@"adding", err);
         }
-    } else {
-        logError(@"getting", err);
     }
+    
     return (err == noErr);
 }
 

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Bibdesk-commit mailing list
Bibdesk-commit@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit

Reply via email to