Last active
November 12, 2022 08:31
-
-
Save franzwong/447611f46e6714cf2f1a082e3879c0f0 to your computer and use it in GitHub Desktop.
Get generic password from MacOS Keychain with C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Build: gcc -framework Security -framework Foundation -o get_generic_password get_generic_password.c | |
// Usage: ./get_generic_password <service name> | |
#include <CoreFoundation/CoreFoundation.h> | |
#include <Security/Security.h> | |
OSStatus getCredentialByServiceName(const char *serviceName, CFTypeRef *credential) { | |
CFStringRef cfServiceName = CFStringCreateWithCString(kCFAllocatorDefault, serviceName, kCFStringEncodingUTF8); | |
const void* keys[] = { kSecClass, kSecAttrService, kSecReturnAttributes, kSecReturnData, kSecMatchLimit }; | |
const void* values[] = { kSecClassGenericPassword, cfServiceName, kCFBooleanTrue, kCFBooleanTrue, kSecMatchLimitOne }; | |
CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, (const void**) keys, (const void**) values, 5, NULL, NULL); | |
OSStatus result = SecItemCopyMatching(query, credential); | |
CFRelease(cfServiceName); | |
CFRelease(query); | |
return result; | |
} | |
void getString(CFStringRef cfString, char **buffer) { | |
const char *str = CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8); | |
if (str != NULL) { | |
*buffer = malloc(strlen(str) + 1); | |
strcpy(*buffer, str); | |
} else { | |
CFIndex length = CFStringGetLength(cfString); | |
CFIndex stringLength = length * sizeof(UniChar) + 1; | |
*buffer = malloc(stringLength); | |
CFStringGetCString(cfString, *buffer, stringLength, kCFStringEncodingUTF8); | |
} | |
} | |
int main(int argc, const char* argv[]) { | |
if (argc < 2) { | |
fprintf(stderr, "Usage: ./get_generic_password <service name>"); | |
return 1; | |
} | |
const char *serviceName = argv[1]; | |
CFTypeRef credential = NULL; | |
OSStatus result = getCredentialByServiceName(serviceName, &credential); | |
if (result == errSecSuccess) { | |
CFStringRef cfAccount = (CFStringRef) CFDictionaryGetValue(credential, kSecAttrAccount); | |
if (cfAccount != NULL) { | |
char *account = NULL; | |
getString(cfAccount, &account); | |
printf("Account: %s\n", account); | |
free(account); | |
} | |
CFDataRef cfPassword = (CFDataRef) CFDictionaryGetValue(credential, kSecValueData); | |
if (cfPassword != NULL) { | |
long length = CFDataGetLength(cfPassword); | |
uint8_t *buffer = malloc(length); | |
CFDataGetBytes(cfPassword, CFRangeMake(0, length), buffer); | |
printf("Password: %.*s\n", (int)length, buffer); | |
free(buffer); | |
buffer = NULL; | |
} | |
CFRelease(credential); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment