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