From: "Marc Becker via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Marc Becker <becm@gmx.de>, Marc Becker <becm@gmx.de>
Subject: [PATCH] wincred: fix line split of secret blob content
Date: Fri, 09 Oct 2026 13:45:18 +0000 [thread overview]
Message-ID: <pull.2251.git.1791553518774.gitgitgadget@gmail.com> (raw)
From: Marc Becker <becm@gmx.de>
operate on immutable blob data (wcsncpy_s still had invalid target size)
split on newline character to avoid bleed-over on multi-line content
Signed-off-by: Marc Becker <becm@gmx.de>
---
wincred: fix line split of secret blob content
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2251%2Fbecm%2Ffix-wincred-secret-linesplit-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2251/becm/fix-wincred-secret-linesplit-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2251
.../wincred/git-credential-wincred.c | 86 ++++++++++++-------
1 file changed, 55 insertions(+), 31 deletions(-)
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 22eb27ca31..584f457774 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
+#include <wchar.h>
#include <wincred.h>
/* common helpers */
@@ -148,51 +149,74 @@ static void get_credential(void)
{
CREDENTIALW **creds;
DWORD num_creds;
- int i;
- CREDENTIAL_ATTRIBUTEW *attr;
- WCHAR *secret;
- WCHAR *line;
- WCHAR *remaining_lines;
- WCHAR *part;
- WCHAR *remaining_parts;
if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
return;
- /* search for the first credential that matches username */
- for (i = 0; i < num_creds; ++i)
+ /* search for the first credential that matches target and username */
+ for (int i = 0; i < num_creds; ++i) {
if (match_cred(creds[i], 0)) {
- write_item("username", creds[i]->UserName,
- creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
- if (creds[i]->CredentialBlobSize > 0) {
- secret = xmalloc(creds[i]->CredentialBlobSize + sizeof(WCHAR));
- wcsncpy_s(secret, creds[i]->CredentialBlobSize, (LPCWSTR)creds[i]->CredentialBlob, creds[i]->CredentialBlobSize / sizeof(WCHAR));
- line = wcstok_s(secret, L"\r\n", &remaining_lines);
- write_item("password", line, line ? wcslen(line) : 0);
- while(line != NULL) {
- part = wcstok_s(line, L"=", &remaining_parts);
- if (!wcscmp(part, L"oauth_refresh_token")) {
- write_item("oauth_refresh_token", remaining_parts, remaining_parts ? wcslen(remaining_parts) : 0);
- }
- line = wcstok_s(NULL, L"\r\n", &remaining_lines);
- }
- free(secret);
+ LPCWSTR username = creds[i]->UserName;
+ LPCWSTR blob = (LPCWSTR)creds[i]->CredentialBlob;
+ LPCWSTR end;
+ DWORD wlen;
+
+ write_item("username", username, username ? wcslen(username) : 0);
+
+ wlen = creds[i]->CredentialBlobSize / sizeof(WCHAR);
+
+ // check if content is single line
+ if ((end = wmemchr(blob, '\n', wlen)) == NULL) {
+ write_item("password", blob, wlen);
} else {
- write_item("password",
- (LPCWSTR)creds[i]->CredentialBlob,
- creds[i]->CredentialBlobSize / sizeof(WCHAR));
+ DWORD length = end++ - blob;
+
+ // correct remaining size and drop carriage return at line end
+ wlen -= length + 1;
+ if (length && blob[length - 1] == '\r') {
+ --length;
+ }
+ write_item("password", blob, length);
+
+ // key/value content starting on next line
+ blob = end;
+ do {
+ LPCWSTR value;
+
+ // find line end
+ if ((end = wmemchr(blob, '\n', wlen)) == NULL) {
+ length = wlen;
+ } else {
+ length = end++ - blob;
+ // correct remaining size and drop carriage return at line end
+ wlen -= length + 1;
+ if (length && blob[length - 1] == '\r') {
+ --length;
+ }
+ }
+ // find key/value separator for extended credential info
+ if ((value = wmemchr(blob, '=', length)) != NULL) {
+ static const LPCWSTR refresh = L"oauth_refresh_token";
+ DWORD klen = value - blob;
+
+ // write entries known to git credential protocol
+ if (klen == wcslen(refresh) && memcmp(blob, refresh, klen) == 0) {
+ write_item("oauth_refresh_token", value + 1, length - klen - 1);
+ }
+ }
+ } while ((blob = end));
}
for (int j = 0; j < creds[i]->AttributeCount; j++) {
- attr = creds[i]->Attributes + j;
+ CREDENTIAL_ATTRIBUTEW *attr = creds[i]->Attributes + j;
+
if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) {
- write_item("password_expiry_utc", (LPCWSTR)attr->Value,
- attr->ValueSize / sizeof(WCHAR));
+ write_item("password_expiry_utc", (LPCWSTR)attr->Value, attr->ValueSize / sizeof(WCHAR));
break;
}
}
break;
}
-
+ }
CredFree(creds);
}
base-commit: 6de20f6092dcf9bdb1c8efe03db4b70c82b423dd
--
gitgitgadget
next reply other threads:[~2026-10-09 13:45 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 13:45 Marc Becker via GitGitGadget [this message]
2026-10-09 21:16 ` [PATCH] wincred: fix line split of secret blob content Junio C Hamano
2026-10-10 11:47 ` [PATCH v2] wincred: refactor credential blob processing Marc Becker via GitGitGadget
2026-10-12 21:27 ` [PATCH v3] " Marc Becker via GitGitGadget
2026-10-12 21:57 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.2251.git.1791553518774.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=becm@gmx.de \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.