Skip to content

Commit

Permalink
osxkeychain: store new attributes
Browse files Browse the repository at this point in the history
d208bfd (credential: new attribute password_expiry_utc, 2023-02-18)
and a5c7656 (credential: new attribute oauth_refresh_token,
2023-04-21) introduced new credential attributes but support was missing
from git-credential-osxkeychain.

Support these attributes by appending the data to the password in the
keychain, separated by line breaks. Line breaks cannot appear in a git
credential password so it is an appropriate separator.

Fixes the remaining test failures with osxkeychain:

    18 - helper (osxkeychain) gets password_expiry_utc
    19 - helper (osxkeychain) overwrites when password_expiry_utc
    changes
    21 - helper (osxkeychain) gets oauth_refresh_token

Signed-off-by: Bo Anderson <mail@boanderson.me>
  • Loading branch information
Bo98 committed Feb 17, 2024
1 parent a9231bf commit 44fad27
Showing 1 changed file with 62 additions and 6 deletions.
68 changes: 62 additions & 6 deletions contrib/credential/osxkeychain/git-credential-osxkeychain.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@
#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 CFNumberRef port;
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;
Expand All @@ -29,12 +35,18 @@ static void clear_credential(void)
CFRelease(password);
password = NULL;
}
if (port) {
CFRelease(port);
port = 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 void die(const char *err, ...)
{
Expand Down Expand Up @@ -197,9 +209,27 @@ static OSStatus delete_ref(const void *itemRef)
CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
result = SecItemCopyMatching(query, (CFTypeRef *)&data);
if (!result) {
if (CFEqual(data, password))
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);
}

Expand Down Expand Up @@ -250,14 +280,31 @@ static OSStatus delete_internet_password(void)

static OSStatus add_internet_password(void)
{
CFMutableDataRef data;
CFDictionaryRef attrs;
OSStatus result;

/* Only store complete credentials */
if (!protocol || !host || !username || !password)
return -1;

attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, password,
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);
Expand All @@ -268,6 +315,7 @@ static OSStatus add_internet_password(void)
CFRelease(query);
}

CFRelease(data);
CFRelease(attrs);

return result;
Expand Down Expand Up @@ -339,6 +387,14 @@ static void read_credential(void)
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));
/*
* Ignore other lines; we don't know what they mean, but
* this future-proofs us when later versions of git do
Expand Down

0 comments on commit 44fad27

Please sign in to comment.