|
6 | 6 | #include <stdio.h> |
7 | 7 | #include <io.h> |
8 | 8 | #include <fcntl.h> |
| 9 | +#include <wchar.h> |
9 | 10 | #include <wincred.h> |
10 | 11 |
|
11 | 12 | /* common helpers */ |
@@ -69,6 +70,72 @@ static void write_item(const char *what, LPCWSTR wbuf, int wlen) |
69 | 70 | free(buf); |
70 | 71 | } |
71 | 72 |
|
| 73 | +/* |
| 74 | + * Write known credential item. |
| 75 | + */ |
| 76 | +static void write_credential_item(LPCWSTR data, int wlen) |
| 77 | +{ |
| 78 | + static const LPCWSTR refresh_token = L"oauth_refresh_token"; |
| 79 | + LPCWSTR value; |
| 80 | + DWORD klen; |
| 81 | + DWORD vlen; |
| 82 | + |
| 83 | + /* find key/value separator for credential item */ |
| 84 | + if ((value = wmemchr(data, L'=', wlen)) == NULL) |
| 85 | + return; |
| 86 | + klen = value++ - data; |
| 87 | + vlen = wlen - klen - 1; |
| 88 | + |
| 89 | + /* write items known to git credential protocol */ |
| 90 | + if (klen == wcslen(refresh_token) && wmemcmp(data, refresh_token, klen) == 0) |
| 91 | + write_item("oauth_refresh_token", value, vlen); |
| 92 | +} |
| 93 | + |
| 94 | +/* |
| 95 | + * Write single credential block |
| 96 | + * consisting of password and further (accepted) credential items. |
| 97 | + */ |
| 98 | +static void write_credential(const CREDENTIALW *cred) |
| 99 | +{ |
| 100 | + LPCWSTR end; |
| 101 | + DWORD length; |
| 102 | + LPCWSTR blob = (LPCWSTR)cred->CredentialBlob; |
| 103 | + DWORD wlen = cred->CredentialBlobSize / sizeof(WCHAR); |
| 104 | + |
| 105 | + /* check if content is single line */ |
| 106 | + if ((end = wmemchr(blob, L'\n', wlen)) == NULL) { |
| 107 | + write_item("password", blob, wlen); |
| 108 | + return; |
| 109 | + } |
| 110 | + /* determine current line length and remaining data size */ |
| 111 | + length = end++ - blob; |
| 112 | + wlen -= length + 1; |
| 113 | + |
| 114 | + /* skip carriage return at line end */ |
| 115 | + if (length && blob[length - 1] == L'\r') |
| 116 | + --length; |
| 117 | + write_item("password", blob, length); |
| 118 | + |
| 119 | + while (1) { |
| 120 | + /* key/value content starts on next line */ |
| 121 | + blob = end; |
| 122 | + |
| 123 | + /* find line end */ |
| 124 | + if ((end = wmemchr(blob, L'\n', wlen)) == NULL) { |
| 125 | + write_credential_item(blob, wlen); |
| 126 | + return; |
| 127 | + } |
| 128 | + /* determine current line length and remaining data size */ |
| 129 | + length = end++ - blob; |
| 130 | + wlen -= length + 1; |
| 131 | + |
| 132 | + // skip carriage return at line end |
| 133 | + if (length && blob[length - 1] == L'\r') |
| 134 | + --length; |
| 135 | + write_credential_item(blob, length); |
| 136 | + } |
| 137 | +} |
| 138 | + |
72 | 139 | /* |
73 | 140 | * Match an (optional) expected string and a delimiter in the target string, |
74 | 141 | * consuming the matched text by updating the target pointer. |
@@ -148,51 +215,32 @@ static void get_credential(void) |
148 | 215 | { |
149 | 216 | CREDENTIALW **creds; |
150 | 217 | DWORD num_creds; |
151 | | - int i; |
152 | | - CREDENTIAL_ATTRIBUTEW *attr; |
153 | | - WCHAR *secret; |
154 | | - WCHAR *line; |
155 | | - WCHAR *remaining_lines; |
156 | | - WCHAR *part; |
157 | | - WCHAR *remaining_parts; |
158 | 218 |
|
159 | 219 | if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds)) |
160 | 220 | return; |
161 | 221 |
|
162 | | - /* search for the first credential that matches username */ |
163 | | - for (i = 0; i < num_creds; ++i) |
164 | | - if (match_cred(creds[i], 0)) { |
165 | | - write_item("username", creds[i]->UserName, |
166 | | - creds[i]->UserName ? wcslen(creds[i]->UserName) : 0); |
167 | | - if (creds[i]->CredentialBlobSize > 0) { |
168 | | - secret = xmalloc(creds[i]->CredentialBlobSize + sizeof(WCHAR)); |
169 | | - wcsncpy_s(secret, creds[i]->CredentialBlobSize, (LPCWSTR)creds[i]->CredentialBlob, creds[i]->CredentialBlobSize / sizeof(WCHAR)); |
170 | | - line = wcstok_s(secret, L"\r\n", &remaining_lines); |
171 | | - write_item("password", line, line ? wcslen(line) : 0); |
172 | | - while(line != NULL) { |
173 | | - part = wcstok_s(line, L"=", &remaining_parts); |
174 | | - if (!wcscmp(part, L"oauth_refresh_token")) { |
175 | | - write_item("oauth_refresh_token", remaining_parts, remaining_parts ? wcslen(remaining_parts) : 0); |
176 | | - } |
177 | | - line = wcstok_s(NULL, L"\r\n", &remaining_lines); |
178 | | - } |
179 | | - free(secret); |
180 | | - } else { |
181 | | - write_item("password", |
182 | | - (LPCWSTR)creds[i]->CredentialBlob, |
183 | | - creds[i]->CredentialBlobSize / sizeof(WCHAR)); |
184 | | - } |
185 | | - for (int j = 0; j < creds[i]->AttributeCount; j++) { |
186 | | - attr = creds[i]->Attributes + j; |
187 | | - if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) { |
188 | | - write_item("password_expiry_utc", (LPCWSTR)attr->Value, |
189 | | - attr->ValueSize / sizeof(WCHAR)); |
190 | | - break; |
191 | | - } |
| 222 | + /* search for the first credential that matches target and username */ |
| 223 | + for (int i = 0; i < num_creds; ++i) { |
| 224 | + LPCWSTR username; |
| 225 | + |
| 226 | + if (!match_cred(creds[i], 0)) |
| 227 | + continue; |
| 228 | + |
| 229 | + username = creds[i]->UserName; |
| 230 | + write_item("username", username, username ? wcslen(username) : 0); |
| 231 | + |
| 232 | + write_credential(creds[i]); |
| 233 | + |
| 234 | + for (int j = 0; j < creds[i]->AttributeCount; j++) { |
| 235 | + CREDENTIAL_ATTRIBUTEW *attr = creds[i]->Attributes + j; |
| 236 | + |
| 237 | + if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) { |
| 238 | + write_item("password_expiry_utc", (LPCWSTR)attr->Value, attr->ValueSize / sizeof(WCHAR)); |
| 239 | + break; |
192 | 240 | } |
193 | | - break; |
194 | 241 | } |
195 | | - |
| 242 | + break; |
| 243 | + } |
196 | 244 | CredFree(creds); |
197 | 245 | } |
198 | 246 |
|
|
0 commit comments