Skip to content

Commit c298848

Browse files
committed
credential/wincred: store oauth_refresh_token
a5c7656 (credential: new attribute oauth_refresh_token) introduced a new confidential credential attribute for helpers to store. We encode the new attribute in the CredentialBlob, separated by newline: hunter2 oauth_refresh_token=xyzzy This is extensible and backwards compatible. The credential protocol already assumes that attribute values do not contain newlines. Alternatives considered: store oauth_refresh_token in a wincred attribute. This would be insecure because wincred assumes attribute values to be non-confidential. Signed-off-by: M Hickford <mirth.hickford@gmail.com>
1 parent bc52045 commit c298848

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

contrib/credential/wincred/git-credential-wincred.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ static void *xmalloc(size_t size)
3535
}
3636

3737
static WCHAR *wusername, *password, *protocol, *host, *path, target[1024],
38-
*password_expiry_utc;
38+
*password_expiry_utc, *oauth_refresh_token;
3939

4040
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
4141
{
@@ -140,6 +140,11 @@ static void get_credential(void)
140140
DWORD num_creds;
141141
int i;
142142
CREDENTIAL_ATTRIBUTEW *attr;
143+
WCHAR *secret;
144+
WCHAR *line;
145+
WCHAR *remaining_lines;
146+
WCHAR *part;
147+
WCHAR *remaining_parts;
143148

144149
if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
145150
return;
@@ -149,9 +154,17 @@ static void get_credential(void)
149154
if (match_cred(creds[i], 0)) {
150155
write_item("username", creds[i]->UserName,
151156
creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
152-
write_item("password",
153-
(LPCWSTR)creds[i]->CredentialBlob,
154-
creds[i]->CredentialBlobSize / sizeof(WCHAR));
157+
secret = xmalloc(creds[i]->CredentialBlobSize);
158+
wcsncpy_s(secret, creds[i]->CredentialBlobSize, (LPCWSTR)creds[i]->CredentialBlob, creds[i]->CredentialBlobSize / sizeof(WCHAR));
159+
line = wcstok_s(secret, L"\r\n", &remaining_lines);
160+
write_item("password", line, wcslen(line));
161+
while(line != NULL) {
162+
part = wcstok_s(line, L"=", &remaining_parts);
163+
if (!wcscmp(part, L"oauth_refresh_token")) {
164+
write_item("oauth_refresh_token", remaining_parts, wcslen(remaining_parts));
165+
}
166+
line = wcstok_s(NULL, L"\r\n", &remaining_lines);
167+
}
155168
for (int j = 0; j < creds[i]->AttributeCount; j++) {
156169
attr = creds[i]->Attributes + j;
157170
if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) {
@@ -160,6 +173,7 @@ static void get_credential(void)
160173
break;
161174
}
162175
}
176+
free(secret);
163177
break;
164178
}
165179

@@ -170,16 +184,26 @@ static void store_credential(void)
170184
{
171185
CREDENTIALW cred;
172186
CREDENTIAL_ATTRIBUTEW expiry_attr;
187+
WCHAR *secret;
188+
int wlen;
173189

174190
if (!wusername || !password)
175191
return;
176192

193+
if (oauth_refresh_token) {
194+
wlen = _scwprintf(L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
195+
secret = xmalloc(sizeof(WCHAR) * wlen);
196+
_snwprintf_s(secret, sizeof(WCHAR) * wlen, wlen, L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
197+
} else {
198+
secret = _wcsdup(password);
199+
}
200+
177201
cred.Flags = 0;
178202
cred.Type = CRED_TYPE_GENERIC;
179203
cred.TargetName = target;
180204
cred.Comment = L"saved by git-credential-wincred";
181-
cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR);
182-
cred.CredentialBlob = (LPVOID)password;
205+
cred.CredentialBlobSize = wcslen(secret) * sizeof(WCHAR);
206+
cred.CredentialBlob = (LPVOID)_wcsdup(secret);
183207
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
184208
cred.AttributeCount = 0;
185209
cred.Attributes = NULL;
@@ -194,6 +218,8 @@ static void store_credential(void)
194218
cred.TargetAlias = NULL;
195219
cred.UserName = wusername;
196220

221+
free(secret);
222+
197223
if (!CredWriteW(&cred, 0))
198224
die("CredWrite failed");
199225
}
@@ -265,6 +291,8 @@ static void read_credential(void)
265291
password = utf8_to_utf16_dup(v);
266292
else if (!strcmp(buf, "password_expiry_utc"))
267293
password_expiry_utc = utf8_to_utf16_dup(v);
294+
else if (!strcmp(buf, "oauth_refresh_token"))
295+
oauth_refresh_token = utf8_to_utf16_dup(v);
268296
/*
269297
* Ignore other lines; we don't know what they mean, but
270298
* this future-proofs us when later versions of git do

0 commit comments

Comments
 (0)