From d467d79c362cb07dc10df074d94c3b13ae547d0d Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 30 Apr 2024 06:53:17 +0800 Subject: [PATCH] Revert "osxkeychain: store new attributes" This reverts commit d5b35bba86e6fdf0484ea71bf5b8ef1167f14015. Revert "osxkeychain: erase matching passwords only" This reverts commit e3cef40db89f5a7c91f4e9d6c4959ca1e41f4647. Revert "osxkeychain: erase all matching credentials" This reverts commit 9032bcad82f45a403e4a8de86e1fcb4bfd1ab282. Revert "osxkeychain: replace deprecated SecKeychain API" This reverts commit 9abe31f5f161be4d69118bdfae00103cd6efa510. --- contrib/credential/osxkeychain/Makefile | 3 +- .../osxkeychain/git-credential-osxkeychain.c | 376 ++++-------------- 2 files changed, 69 insertions(+), 310 deletions(-) diff --git contrib/credential/osxkeychain/Makefile contrib/credential/osxkeychain/Makefile index 238f5f8c36..4b3a08a2ba 100644 --- a/contrib/credential/osxkeychain/Makefile +++ b/contrib/credential/osxkeychain/Makefile @@ -8,8 +8,7 @@ CFLAGS = -g -O2 -Wall -include ../../../config.mak git-credential-osxkeychain: git-credential-osxkeychain.o - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) \ - -framework Security -framework CoreFoundation + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -Wl,-framework -Wl,Security git-credential-osxkeychain.o: git-credential-osxkeychain.c $(CC) -c $(CFLAGS) $< diff --git contrib/credential/osxkeychain/git-credential-osxkeychain.c contrib/credential/osxkeychain/git-credential-osxkeychain.c index 6a40917b1e..5f2e5f16c8 100644 --- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c +++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c @@ -3,51 +3,14 @@ #include #include -#define ENCODING kCFStringEncodingUTF8 -static CFStringRef protocol; /* Stores constant strings - not memory managed */ -static CFStringRef host; -static CFNumberRef port; -static CFStringRef path; -static CFStringRef username; -static CFDataRef password; -static CFDataRef password_expiry_utc; -static CFDataRef oauth_refresh_token; - -static void clear_credential(void) -{ - if (host) { - CFRelease(host); - host = NULL; - } - if (port) { - CFRelease(port); - port = NULL; - } - if (path) { - CFRelease(path); - path = NULL; - } - if (username) { - CFRelease(username); - username = NULL; - } - if (password) { - CFRelease(password); - password = NULL; - } - if (password_expiry_utc) { - CFRelease(password_expiry_utc); - password_expiry_utc = NULL; - } - if (oauth_refresh_token) { - CFRelease(oauth_refresh_token); - oauth_refresh_token = NULL; - } -} - -#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1 - -__attribute__((format (printf, 1, 2), __noreturn__)) +static SecProtocolType protocol; +static char *host; +static char *path; +static char *username; +static char *password; +static UInt16 port; + +__attribute__((format (printf, 1, 2))) static void die(const char *err, ...) { char msg[4096]; @@ -56,199 +19,70 @@ static void die(const char *err, ...) vsnprintf(msg, sizeof(msg), err, params); fprintf(stderr, "%s\n", msg); va_end(params); - clear_credential(); exit(1); } -static void *xmalloc(size_t len) +static void *xstrdup(const char *s1) { - void *ret = malloc(len); + void *ret = strdup(s1); if (!ret) die("Out of memory"); return ret; } -static CFDictionaryRef create_dictionary(CFAllocatorRef allocator, ...) -{ - va_list args; - const void *key; - CFMutableDictionaryRef result; - - result = CFDictionaryCreateMutable(allocator, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - - va_start(args, allocator); - while ((key = va_arg(args, const void *)) != NULL) { - const void *value; - value = va_arg(args, const void *); - if (value) - CFDictionarySetValue(result, key, value); - } - va_end(args); - - return result; -} - -#define CREATE_SEC_ATTRIBUTES(...) \ - create_dictionary(kCFAllocatorDefault, \ - kSecClass, kSecClassInternetPassword, \ - kSecAttrServer, host, \ - kSecAttrAccount, username, \ - kSecAttrPath, path, \ - kSecAttrPort, port, \ - kSecAttrProtocol, protocol, \ - kSecAttrAuthenticationType, \ - kSecAttrAuthenticationTypeDefault, \ - __VA_ARGS__); - -static void write_item(const char *what, const char *buf, size_t len) +#define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x +#define KEYCHAIN_ARGS \ + NULL, /* default keychain */ \ + KEYCHAIN_ITEM(host), \ + 0, NULL, /* account domain */ \ + KEYCHAIN_ITEM(username), \ + KEYCHAIN_ITEM(path), \ + port, \ + protocol, \ + kSecAuthenticationTypeDefault + +static void write_item(const char *what, const char *buf, int len) { printf("%s=", what); fwrite(buf, 1, len, stdout); putchar('\n'); } -static void find_username_in_item(CFDictionaryRef item) +static void find_username_in_item(SecKeychainItemRef item) { - CFStringRef account_ref; - char *username_buf; - CFIndex buffer_len; + SecKeychainAttributeList list; + SecKeychainAttribute attr; - account_ref = CFDictionaryGetValue(item, kSecAttrAccount); - if (!account_ref) - { - write_item("username", "", 0); - return; - } + list.count = 1; + list.attr = &attr; + attr.tag = kSecAccountItemAttr; - username_buf = (char *)CFStringGetCStringPtr(account_ref, ENCODING); - if (username_buf) - { - write_item("username", username_buf, strlen(username_buf)); + if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL)) return; - } - /* If we can't get a CString pointer then - * we need to allocate our own buffer */ - buffer_len = CFStringGetMaximumSizeForEncoding( - CFStringGetLength(account_ref), ENCODING) + 1; - username_buf = xmalloc(buffer_len); - if (CFStringGetCString(account_ref, - username_buf, - buffer_len, - ENCODING)) { - write_item("username", username_buf, buffer_len - 1); - } - free(username_buf); + write_item("username", attr.data, attr.length); + SecKeychainItemFreeContent(&list, NULL); } -static OSStatus find_internet_password(void) +static void find_internet_password(void) { - CFDictionaryRef attrs; - CFDictionaryRef item; - CFDataRef data; - OSStatus result; - - attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitOne, - kSecReturnAttributes, kCFBooleanTrue, - kSecReturnData, kCFBooleanTrue, - NULL); - result = SecItemCopyMatching(attrs, (CFTypeRef *)&item); - if (result) { - goto out; - } + void *buf; + UInt32 len; + SecKeychainItemRef item; - data = CFDictionaryGetValue(item, kSecValueData); + if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item)) + return; - write_item("password", - (const char *)CFDataGetBytePtr(data), - CFDataGetLength(data)); + write_item("password", buf, len); if (!username) find_username_in_item(item); - CFRelease(item); - -out: - CFRelease(attrs); - - /* We consider not found to not be an error */ - if (result == errSecItemNotFound) - result = errSecSuccess; - - 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) { - CFDataRef kc_password; - const UInt8 *raw_data; - const UInt8 *line; - - /* Don't match appended metadata */ - raw_data = CFDataGetBytePtr(data); - line = memchr(raw_data, '\n', CFDataGetLength(data)); - if (line) - kc_password = CFDataCreateWithBytesNoCopy( - kCFAllocatorDefault, - raw_data, - line - raw_data, - kCFAllocatorNull); - else - kc_password = data; - - if (CFEqual(kc_password, password)) - result = SecItemDelete(delete_query); - - if (line) - CFRelease(kc_password); - CFRelease(data); - } - - CFRelease(query); - } else { - result = SecItemDelete(delete_query); - } - - CFRelease(delete_query); - CFRelease(item_ref_list); - - return result; + SecKeychainItemFreeContent(NULL, buf); } -static OSStatus delete_internet_password(void) +static void delete_internet_password(void) { - CFDictionaryRef attrs; - CFArrayRef refs; - OSStatus result; + SecKeychainItemRef item; /* * Require at least a protocol and host for removal, which is what git @@ -256,69 +90,25 @@ static OSStatus delete_internet_password(void) * Keychain manager. */ if (!protocol || !host) - return -1; - - attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitAll, - kSecReturnRef, kCFBooleanTrue, - NULL); - 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); - } + return; - /* We consider not found to not be an error */ - if (result == errSecItemNotFound) - result = errSecSuccess; + if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item)) + return; - return result; + SecKeychainItemDelete(item); } -static OSStatus add_internet_password(void) +static void add_internet_password(void) { - CFMutableDataRef data; - CFDictionaryRef attrs; - OSStatus result; - /* Only store complete credentials */ if (!protocol || !host || !username || !password) - return -1; - - data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password); - if (password_expiry_utc) { - CFDataAppendBytes(data, - (const UInt8 *)STRING_WITH_LENGTH("\npassword_expiry_utc=")); - CFDataAppendBytes(data, - CFDataGetBytePtr(password_expiry_utc), - CFDataGetLength(password_expiry_utc)); - } - if (oauth_refresh_token) { - CFDataAppendBytes(data, - (const UInt8 *)STRING_WITH_LENGTH("\noauth_refresh_token=")); - CFDataAppendBytes(data, - CFDataGetBytePtr(oauth_refresh_token), - CFDataGetLength(oauth_refresh_token)); - } - - attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, data, - NULL); - - result = SecItemAdd(attrs, NULL); - if (result == errSecDuplicateItem) { - CFDictionaryRef query; - query = CREATE_SEC_ATTRIBUTES(NULL); - result = SecItemUpdate(query, attrs); - CFRelease(query); - } - - CFRelease(data); - CFRelease(attrs); + return; - return result; + if (SecKeychainAddInternetPassword( + KEYCHAIN_ARGS, + KEYCHAIN_ITEM(password), + NULL)) + return; } static void read_credential(void) @@ -341,60 +131,36 @@ static void read_credential(void) if (!strcmp(buf, "protocol")) { if (!strcmp(v, "imap")) - protocol = kSecAttrProtocolIMAP; + protocol = kSecProtocolTypeIMAP; else if (!strcmp(v, "imaps")) - protocol = kSecAttrProtocolIMAPS; + protocol = kSecProtocolTypeIMAPS; else if (!strcmp(v, "ftp")) - protocol = kSecAttrProtocolFTP; + protocol = kSecProtocolTypeFTP; else if (!strcmp(v, "ftps")) - protocol = kSecAttrProtocolFTPS; + protocol = kSecProtocolTypeFTPS; else if (!strcmp(v, "https")) - protocol = kSecAttrProtocolHTTPS; + protocol = kSecProtocolTypeHTTPS; else if (!strcmp(v, "http")) - protocol = kSecAttrProtocolHTTP; + protocol = kSecProtocolTypeHTTP; else if (!strcmp(v, "smtp")) - protocol = kSecAttrProtocolSMTP; - else { - /* we don't yet handle other protocols */ - clear_credential(); + protocol = kSecProtocolTypeSMTP; + else /* we don't yet handle other protocols */ exit(0); - } } else if (!strcmp(buf, "host")) { char *colon = strchr(v, ':'); if (colon) { - UInt16 port_i; *colon++ = '\0'; - port_i = atoi(colon); - port = CFNumberCreate(kCFAllocatorDefault, - kCFNumberShortType, - &port_i); + port = atoi(colon); } - host = CFStringCreateWithCString(kCFAllocatorDefault, - v, - ENCODING); + host = xstrdup(v); } else if (!strcmp(buf, "path")) - path = CFStringCreateWithCString(kCFAllocatorDefault, - v, - ENCODING); + path = xstrdup(v); else if (!strcmp(buf, "username")) - username = CFStringCreateWithCString( - kCFAllocatorDefault, - v, - ENCODING); + username = xstrdup(v); else if (!strcmp(buf, "password")) - password = CFDataCreate(kCFAllocatorDefault, - (UInt8 *)v, - strlen(v)); - else if (!strcmp(buf, "password_expiry_utc")) - password_expiry_utc = CFDataCreate(kCFAllocatorDefault, - (UInt8 *)v, - strlen(v)); - else if (!strcmp(buf, "oauth_refresh_token")) - oauth_refresh_token = CFDataCreate(kCFAllocatorDefault, - (UInt8 *)v, - strlen(v)); + password = xstrdup(v); /* * Ignore other lines; we don't know what they mean, but * this future-proofs us when later versions of git do @@ -407,7 +173,6 @@ static void read_credential(void) int main(int argc, const char **argv) { - OSStatus result = 0; const char *usage = "usage: git credential-osxkeychain "; @@ -417,17 +182,12 @@ int main(int argc, const char **argv) read_credential(); if (!strcmp(argv[1], "get")) - result = find_internet_password(); + find_internet_password(); else if (!strcmp(argv[1], "store")) - result = add_internet_password(); + add_internet_password(); else if (!strcmp(argv[1], "erase")) - result = delete_internet_password(); + delete_internet_password(); /* otherwise, ignore unknown action */ - if (result) - die("failed to %s: %d", argv[1], (int)result); - - clear_credential(); - return 0; }