Git development
 help / color / mirror / Atom feed
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

             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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox