aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBo Anderson <mail@boanderson.me>2024-02-17 23:34:55 +0000
committerJunio C Hamano <gitster@pobox.com>2024-04-01 15:38:20 -0700
commite3cef40db89f5a7c91f4e9d6c4959ca1e41f4647 (patch)
tree8d2eb6b353605694002c39ef90c282070fabc6ed
parent9032bcad82f45a403e4a8de86e1fcb4bfd1ab282 (diff)
downloadgit-e3cef40db89f5a7c91f4e9d6c4959ca1e41f4647.tar.gz
osxkeychain: erase matching passwords only
Other credential helpers support deleting credentials that match a specified password. See 7144dee3ec (credential/libsecret: erase matching creds only, 2023-07-26) and cb626f8e5c (credential/wincred: erase matching creds only, 2023-07-26). Support this in osxkeychain too by extracting, decrypting and comparing the stored password before deleting. Fixes the following test failure with osxkeychain: 11 - helper (osxkeychain) does not erase a password distinct from input Signed-off-by: Bo Anderson <mail@boanderson.me> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index e9cee3aed4..9e74279633 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -169,9 +169,55 @@ out:
return result;
}
+static OSStatus delete_ref(const void *itemRef)
+{
+ CFArrayRef item_ref_list;
+ CFDictionaryRef delete_query;
+ OSStatus result;
+
+ item_ref_list = CFArrayCreate(kCFAllocatorDefault,
+ &itemRef,
+ 1,
+ &kCFTypeArrayCallBacks);
+ delete_query = create_dictionary(kCFAllocatorDefault,
+ kSecClass, kSecClassInternetPassword,
+ kSecMatchItemList, item_ref_list,
+ NULL);
+
+ if (password) {
+ /* We only want to delete items with a matching password */
+ CFIndex capacity;
+ CFMutableDictionaryRef query;
+ CFDataRef data;
+
+ capacity = CFDictionaryGetCount(delete_query) + 1;
+ query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
+ capacity,
+ delete_query);
+ CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
+ result = SecItemCopyMatching(query, (CFTypeRef *)&data);
+ if (!result) {
+ if (CFEqual(data, password))
+ result = SecItemDelete(delete_query);
+
+ CFRelease(data);
+ }
+
+ CFRelease(query);
+ } else {
+ result = SecItemDelete(delete_query);
+ }
+
+ CFRelease(delete_query);
+ CFRelease(item_ref_list);
+
+ return result;
+}
+
static OSStatus delete_internet_password(void)
{
CFDictionaryRef attrs;
+ CFArrayRef refs;
OSStatus result;
/*
@@ -183,10 +229,18 @@ static OSStatus delete_internet_password(void)
return -1;
attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitAll,
+ kSecReturnRef, kCFBooleanTrue,
NULL);
- result = SecItemDelete(attrs);
+ result = SecItemCopyMatching(attrs, (CFTypeRef *)&refs);
CFRelease(attrs);
+ if (!result) {
+ for (CFIndex i = 0; !result && i < CFArrayGetCount(refs); i++)
+ result = delete_ref(CFArrayGetValueAtIndex(refs, i));
+
+ CFRelease(refs);
+ }
+
/* We consider not found to not be an error */
if (result == errSecItemNotFound)
result = errSecSuccess;