git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] wincred: improve compatibility with windows versions
@ 2013-01-04 20:28 Karsten Blees
  2013-01-04 21:57 ` Erik Faye-Lund
  0 siblings, 1 reply; 15+ messages in thread
From: Karsten Blees @ 2013-01-04 20:28 UTC (permalink / raw)
  To: git; +Cc: msysgit, kusmabite, Jeff King

On WinXP, the windows credential helper doesn't work at all (due to missing
Cred[Un]PackAuthenticationBuffer APIs). On Win7, the credential format used
by wincred is incompatible with native Windows tools (such as the control
panel applet or 'cmdkey.exe /generic'). These Windows tools only set the
TargetName, UserName and CredentialBlob members of the CREDENTIAL
structure (where CredentialBlob is the UTF-16-encoded password).

Remove the unnecessary packing / unpacking of the password, along with the
related API definitions, for compatibility with Windows XP.

Don't use CREDENTIAL_ATTRIBUTEs to identify credentials for compatibility
with Windows credential manager tools. Parse the protocol, username, host
and path fields from the credential's target name instead.

While we're at it, optionally accept CRLF (instead of LF only) to simplify
debugging in bash / cmd.

Signed-off-by: Karsten Blees <blees@dcon.de>
---

Hi,

I tried the windows credential helper yesterday and found that it doesn't work on XP at all, and doesn't work properly in combination with Win7 credential manager tools. So here's a patch that reduces it to the functionality provided / expected by Windows.

@Erik, Jeff: Please let me know if I'm missing something and the use of Cred[Un]PackAuthenticationBuffer or CREDENTIAL_ATTRIBUTEs actually served a useful purpose.

Cheers,
Karsten

Also available here:
https://github.com/kblees/git/tree/kb/improve-wincred-compatibility
git pull git://github.com/kblees/git.git kb/improve-wincred-compatibility

---
 .../credential/wincred/git-credential-wincred.c    | 179 ++++++---------------
 1 file changed, 53 insertions(+), 126 deletions(-)

diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index cbaec5f..3464080 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -9,6 +9,8 @@
 
 /* common helpers */
 
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
 static void die(const char *err, ...)
 {
 	char msg[4096];
@@ -30,14 +32,6 @@ static void *xmalloc(size_t size)
 	return ret;
 }
 
-static char *xstrdup(const char *str)
-{
-	char *ret = strdup(str);
-	if (!ret)
-		die("Out of memory");
-	return ret;
-}
-
 /* MinGW doesn't have wincred.h, so we need to define stuff */
 
 typedef struct _CREDENTIAL_ATTRIBUTEW {
@@ -67,20 +61,14 @@ typedef struct _CREDENTIALW {
 #define CRED_MAX_ATTRIBUTES 64
 
 typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
-typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
-    LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
 typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
     PCREDENTIALW **);
-typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
-    PBYTE, DWORD *);
 typedef VOID (WINAPI *CredFreeT)(PVOID);
 typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
 
 static HMODULE advapi, credui;
 static CredWriteWT CredWriteW;
-static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
 static CredEnumerateWT CredEnumerateW;
-static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
 static CredFreeT CredFree;
 static CredDeleteWT CredDeleteW;
 
@@ -88,74 +76,64 @@ static void load_cred_funcs(void)
 {
 	/* load DLLs */
 	advapi = LoadLibrary("advapi32.dll");
-	credui = LoadLibrary("credui.dll");
-	if (!advapi || !credui)
+	if (!advapi)
 		die("failed to load DLLs");
 
 	/* get function pointers */
 	CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
-	CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT)
-	    GetProcAddress(credui, "CredUnPackAuthenticationBufferW");
 	CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
 	    "CredEnumerateW");
-	CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT)
-	    GetProcAddress(credui, "CredPackAuthenticationBufferW");
 	CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
 	CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
-	if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
-	    !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
-	    !CredDeleteW)
+	if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW)
 		die("failed to load functions");
 }
 
-static char target_buf[1024];
-static char *protocol, *host, *path, *username;
-static WCHAR *wusername, *password, *target;
+static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
 
-static void write_item(const char *what, WCHAR *wbuf)
+static void write_item(const char *what, LPCWSTR wbuf, int wlen)
 {
 	char *buf;
-	int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
+	int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
 	    FALSE);
 	buf = xmalloc(len);
 
-	if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
+	if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, buf, len, NULL, FALSE))
 		die("WideCharToMultiByte failed!");
 
 	printf("%s=", what);
-	fwrite(buf, 1, len - 1, stdout);
+	fwrite(buf, 1, len, stdout);
 	putchar('\n');
 	free(buf);
 }
 
-static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
-    const char *want)
+static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
 {
-	int i;
-	if (!want)
-		return 1;
-
-	for (i = 0; i < cred->AttributeCount; ++i)
-		if (!wcscmp(cred->Attributes[i].Keyword, keyword))
-			return !strcmp((const char *)cred->Attributes[i].Value,
-			    want);
-
-	return 0; /* not found */
+	LPCWSTR start = *ptarget;
+	LPCWSTR end = *delim ? wcsstr(start, delim) : start + wcslen(start);
+	int len = end ? end - start : wcslen(start);
+	/* update ptarget if we either found a delimiter or need a match */
+	if (end || want)
+		*ptarget = end ? end + wcslen(delim) : start + len;
+	return !want || (!wcsncmp(want, start, len) && !want[len]);
 }
 
 static int match_cred(const CREDENTIALW *cred)
 {
-	return (!wusername || !wcscmp(wusername, cred->UserName)) &&
-	    match_attr(cred, L"git_protocol", protocol) &&
-	    match_attr(cred, L"git_host", host) &&
-	    match_attr(cred, L"git_path", path);
+	LPCWSTR target = cred->TargetName;
+	if (wusername && wcscmp(wusername, cred->UserName))
+		return 0;
+
+	return match_part(&target, L"git", L":") &&
+		match_part(&target, protocol, L"://") &&
+		match_part(&target, wusername, L"@") &&
+		match_part(&target, host, L"/") &&
+		match_part(&target, path, L"");
 }
 
 static void get_credential(void)
 {
-	WCHAR *user_buf, *pass_buf;
-	DWORD user_buf_size = 0, pass_buf_size = 0;
-	CREDENTIALW **creds, *cred = NULL;
+	CREDENTIALW **creds;
 	DWORD num_creds;
 	int i;
 
@@ -165,44 +143,15 @@ static void get_credential(void)
 	/* search for the first credential that matches username */
 	for (i = 0; i < num_creds; ++i)
 		if (match_cred(creds[i])) {
-			cred = creds[i];
+			write_item("username", creds[i]->UserName,
+				wcslen(creds[i]->UserName));
+			write_item("password",
+				(LPCWSTR)creds[i]->CredentialBlob,
+				creds[i]->CredentialBlobSize / sizeof(WCHAR));
 			break;
 		}
-	if (!cred)
-		return;
-
-	CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
-	    cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
-	    NULL, &pass_buf_size);
-
-	user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
-	pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
-
-	if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
-	    cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
-	    pass_buf, &pass_buf_size))
-		die("CredUnPackAuthenticationBuffer failed");
 
 	CredFree(creds);
-
-	/* zero-terminate (sizes include zero-termination) */
-	user_buf[user_buf_size - 1] = L'\0';
-	pass_buf[pass_buf_size - 1] = L'\0';
-
-	write_item("username", user_buf);
-	write_item("password", pass_buf);
-
-	free(user_buf);
-	free(pass_buf);
-}
-
-static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
-    const char *value)
-{
-	attr->Keyword = (LPWSTR)keyword;
-	attr->Flags = 0;
-	attr->ValueSize = strlen(value) + 1; /* store zero-termination */
-	attr->Value = (LPBYTE)value;
 }
 
 static void store_credential(void)
@@ -215,40 +164,18 @@ static void store_credential(void)
 	if (!wusername || !password)
 		return;
 
-	/* query buffer size */
-	CredPackAuthenticationBufferW(0, wusername, password,
-	    NULL, &auth_buf_size);
-
-	auth_buf = xmalloc(auth_buf_size);
-
-	if (!CredPackAuthenticationBufferW(0, wusername, password,
-	    auth_buf, &auth_buf_size))
-		die("CredPackAuthenticationBuffer failed");
-
 	cred.Flags = 0;
 	cred.Type = CRED_TYPE_GENERIC;
 	cred.TargetName = target;
 	cred.Comment = L"saved by git-credential-wincred";
-	cred.CredentialBlobSize = auth_buf_size;
-	cred.CredentialBlob = auth_buf;
+	cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR);
+	cred.CredentialBlob = (LPVOID)password;
 	cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
-	cred.AttributeCount = 1;
-	cred.Attributes = attrs;
+	cred.AttributeCount = 0;
+	cred.Attributes = NULL;
 	cred.TargetAlias = NULL;
 	cred.UserName = wusername;
 
-	write_attr(attrs, L"git_protocol", protocol);
-
-	if (host) {
-		write_attr(attrs + cred.AttributeCount, L"git_host", host);
-		cred.AttributeCount++;
-	}
-
-	if (path) {
-		write_attr(attrs + cred.AttributeCount, L"git_path", path);
-		cred.AttributeCount++;
-	}
-
 	if (!CredWriteW(&cred, 0))
 		die("CredWrite failed");
 }
@@ -284,10 +211,13 @@ static void read_credential(void)
 
 	while (fgets(buf, sizeof(buf), stdin)) {
 		char *v;
+		int len = strlen(buf);
+		/* strip trailing CR / LF */
+		while (len && strchr("\r\n", buf[len - 1]))
+			buf[--len] = 0;
 
-		if (!strcmp(buf, "\n"))
+		if (!*buf)
 			break;
-		buf[strlen(buf)-1] = '\0';
 
 		v = strchr(buf, '=');
 		if (!v)
@@ -295,13 +225,12 @@ static void read_credential(void)
 		*v++ = '\0';
 
 		if (!strcmp(buf, "protocol"))
-			protocol = xstrdup(v);
+			protocol = utf8_to_utf16_dup(v);
 		else if (!strcmp(buf, "host"))
-			host = xstrdup(v);
+			host = utf8_to_utf16_dup(v);
 		else if (!strcmp(buf, "path"))
-			path = xstrdup(v);
+			path = utf8_to_utf16_dup(v);
 		else if (!strcmp(buf, "username")) {
-			username = xstrdup(v);
 			wusername = utf8_to_utf16_dup(v);
 		} else if (!strcmp(buf, "password"))
 			password = utf8_to_utf16_dup(v);
@@ -330,22 +259,20 @@ int main(int argc, char *argv[])
 		return 0;
 
 	/* prepare 'target', the unique key for the credential */
-	strncat(target_buf, "git:", sizeof(target_buf));
-	strncat(target_buf, protocol, sizeof(target_buf));
-	strncat(target_buf, "://", sizeof(target_buf));
-	if (username) {
-		strncat(target_buf, username, sizeof(target_buf));
-		strncat(target_buf, "@", sizeof(target_buf));
+	wcscpy(target, L"git:");
+	wcsncat(target, protocol, ARRAY_SIZE(target));
+	wcsncat(target, L"://", ARRAY_SIZE(target));
+	if (wusername) {
+		wcsncat(target, wusername, ARRAY_SIZE(target));
+		wcsncat(target, L"@", ARRAY_SIZE(target));
 	}
 	if (host)
-		strncat(target_buf, host, sizeof(target_buf));
+		wcsncat(target, host, ARRAY_SIZE(target));
 	if (path) {
-		strncat(target_buf, "/", sizeof(target_buf));
-		strncat(target_buf, path, sizeof(target_buf));
+		wcsncat(target, L"/", ARRAY_SIZE(target));
+		wcsncat(target, path, ARRAY_SIZE(target));
 	}
 
-	target = utf8_to_utf16_dup(target_buf);
-
 	if (!strcmp(argv[1], "get"))
 		get_credential();
 	else if (!strcmp(argv[1], "store"))
-- 
1.8.0.msysgit.0.4.g4e40dea

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] wincred: improve compatibility with windows versions
  2013-01-04 20:28 [PATCH] wincred: improve compatibility with windows versions Karsten Blees
@ 2013-01-04 21:57 ` Erik Faye-Lund
  2013-01-08 16:20   ` Karsten Blees
  0 siblings, 1 reply; 15+ messages in thread
From: Erik Faye-Lund @ 2013-01-04 21:57 UTC (permalink / raw)
  To: blees; +Cc: git, msysgit, Jeff King

On Fri, Jan 4, 2013 at 9:28 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
> On WinXP, the windows credential helper doesn't work at all (due to missing
> Cred[Un]PackAuthenticationBuffer APIs). On Win7, the credential format used
> by wincred is incompatible with native Windows tools (such as the control
> panel applet or 'cmdkey.exe /generic'). These Windows tools only set the
> TargetName, UserName and CredentialBlob members of the CREDENTIAL
> structure (where CredentialBlob is the UTF-16-encoded password).
>
> Remove the unnecessary packing / unpacking of the password, along with the
> related API definitions, for compatibility with Windows XP.
>
> Don't use CREDENTIAL_ATTRIBUTEs to identify credentials for compatibility
> with Windows credential manager tools. Parse the protocol, username, host
> and path fields from the credential's target name instead.
>
> While we're at it, optionally accept CRLF (instead of LF only) to simplify
> debugging in bash / cmd.
>
> Signed-off-by: Karsten Blees <blees@dcon.de>
> ---
>
> Hi,
>
> I tried the windows credential helper yesterday and found that it doesn't work on XP at all, and doesn't work properly in combination with Win7 credential manager tools. So here's a patch that reduces it to the functionality provided / expected by Windows.
>
> @Erik, Jeff: Please let me know if I'm missing something and the use of Cred[Un]PackAuthenticationBuffer or CREDENTIAL_ATTRIBUTEs actually served a useful purpose.
>

The only reason why I used Cred[Un]PackAuthenticationBuffer, were that
I wasn't aware that it was possible any other way. I didn't even know
there was a Windows Credential Manager in Windows XP.

The credential attributes were because they were convenient, and I'm
not sure I understand what you mean about the Win7 credential manager
tools. I did test my code with it - in fact, it was a very useful tool
for debugging the helper.

Are you referring to the credentials not *looking* like normal
HTTP-credentials? If so, I simply didn't see that as a goal. Why would
it be? Compatibility with IE? We already lose that with our "git:"
prefix in the target, no? Perhaps we can lose the "git:"-prefix, and
gain IE-compatibility when the protocol matches?

But, if we do any of these changes, does this mean I will lose my
existing credentials? It's probably not a big deal, but it's worth a
mention, isn't it?

> @@ -67,20 +61,14 @@ typedef struct _CREDENTIALW {
>  #define CRED_MAX_ATTRIBUTES 64
>
>  typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
> -typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
> -    LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
>  typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
>      PCREDENTIALW **);
> -typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
> -    PBYTE, DWORD *);
>  typedef VOID (WINAPI *CredFreeT)(PVOID);
>  typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
>
>  static HMODULE advapi, credui;

Perhaps get rid of credui also?

>  static CredWriteWT CredWriteW;
> -static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
>  static CredEnumerateWT CredEnumerateW;
> -static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
>  static CredFreeT CredFree;
>  static CredDeleteWT CredDeleteW;
>
> @@ -88,74 +76,64 @@ static void load_cred_funcs(void)
>  {
>         /* load DLLs */
>         advapi = LoadLibrary("advapi32.dll");
> -       credui = LoadLibrary("credui.dll");
> -       if (!advapi || !credui)
> +       if (!advapi)
>                 die("failed to load DLLs");

It's not multiple DLLs any more, so perhaps "failed to load
advapi32.dll" instead?

> -static char target_buf[1024];
> -static char *protocol, *host, *path, *username;
> -static WCHAR *wusername, *password, *target;
> +static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
>
> -static void write_item(const char *what, WCHAR *wbuf)
> +static void write_item(const char *what, LPCWSTR wbuf, int wlen)
>  {
>         char *buf;
> -       int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
> +       int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
>             FALSE);
>         buf = xmalloc(len);
>
> -       if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
> +       if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, buf, len, NULL, FALSE))
>                 die("WideCharToMultiByte failed!");
>
>         printf("%s=", what);
> -       fwrite(buf, 1, len - 1, stdout);
> +       fwrite(buf, 1, len, stdout);
>         putchar('\n');
>         free(buf);
>  }
>

When the password-blob is simply UTF-16 encoded, are the
zero-termination not included? That's the reason for this change,
right?

> -static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
> -    const char *want)
> +static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
>  {
> -       int i;
> -       if (!want)
> -               return 1;
> -
> -       for (i = 0; i < cred->AttributeCount; ++i)
> -               if (!wcscmp(cred->Attributes[i].Keyword, keyword))
> -                       return !strcmp((const char *)cred->Attributes[i].Value,
> -                           want);
> -
> -       return 0; /* not found */
> +       LPCWSTR start = *ptarget;
> +       LPCWSTR end = *delim ? wcsstr(start, delim) : start + wcslen(start);
> +       int len = end ? end - start : wcslen(start);
> +       /* update ptarget if we either found a delimiter or need a match */
> +       if (end || want)
> +               *ptarget = end ? end + wcslen(delim) : start + len;
> +       return !want || (!wcsncmp(want, start, len) && !want[len]);
>  }
>

I'm a bit tired now, but I'm having a hard time reading this code.
Right now it seems it's a bit too ternary-expression heavy for my
taste, though.

>  static int match_cred(const CREDENTIALW *cred)
>  {
> -       return (!wusername || !wcscmp(wusername, cred->UserName)) &&
> -           match_attr(cred, L"git_protocol", protocol) &&
> -           match_attr(cred, L"git_host", host) &&
> -           match_attr(cred, L"git_path", path);
> +       LPCWSTR target = cred->TargetName;
> +       if (wusername && wcscmp(wusername, cred->UserName))
> +               return 0;
> +
> +       return match_part(&target, L"git", L":") &&
> +               match_part(&target, protocol, L"://") &&
> +               match_part(&target, wusername, L"@") &&
> +               match_part(&target, host, L"/") &&
> +               match_part(&target, path, L"");
>  }
>

Ugh, it feels a bit wrong to store and verify the username twice. Do
we really have to?

The target needs to be unique, even if two different usernames are
stored for the same site under the same conditions. So probably. It
just doesn't feel quite right.

> @@ -165,44 +143,15 @@ static void get_credential(void)
>         /* search for the first credential that matches username */
>         for (i = 0; i < num_creds; ++i)
>                 if (match_cred(creds[i])) {
> -                       cred = creds[i];
> +                       write_item("username", creds[i]->UserName,
> +                               wcslen(creds[i]->UserName));
> +                       write_item("password",
> +                               (LPCWSTR)creds[i]->CredentialBlob,
> +                               creds[i]->CredentialBlobSize / sizeof(WCHAR));
>                         break;
>                 }
> -       if (!cred)
> -               return;
> -
> -       CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
> -           cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
> -           NULL, &pass_buf_size);
> -
> -       user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
> -       pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
> -
> -       if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
> -           cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
> -           pass_buf, &pass_buf_size))
> -               die("CredUnPackAuthenticationBuffer failed");
>
>         CredFree(creds);
> -
> -       /* zero-terminate (sizes include zero-termination) */
> -       user_buf[user_buf_size - 1] = L'\0';
> -       pass_buf[pass_buf_size - 1] = L'\0';
> -
> -       write_item("username", user_buf);
> -       write_item("password", pass_buf);
> -
> -       free(user_buf);
> -       free(pass_buf);
> -}

Nice!

> -
> -static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
> -    const char *value)
> -{
> -       attr->Keyword = (LPWSTR)keyword;
> -       attr->Flags = 0;
> -       attr->ValueSize = strlen(value) + 1; /* store zero-termination */
> -       attr->Value = (LPBYTE)value;
>  }
>
>  static void store_credential(void)
> @@ -215,40 +164,18 @@ static void store_credential(void)
>         if (!wusername || !password)
>                 return;
>
> -       /* query buffer size */
> -       CredPackAuthenticationBufferW(0, wusername, password,
> -           NULL, &auth_buf_size);
> -
> -       auth_buf = xmalloc(auth_buf_size);
> -
> -       if (!CredPackAuthenticationBufferW(0, wusername, password,
> -           auth_buf, &auth_buf_size))
> -               die("CredPackAuthenticationBuffer failed");
> -
>         cred.Flags = 0;
>         cred.Type = CRED_TYPE_GENERIC;
>         cred.TargetName = target;
>         cred.Comment = L"saved by git-credential-wincred";
> -       cred.CredentialBlobSize = auth_buf_size;
> -       cred.CredentialBlob = auth_buf;
> +       cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR);
> +       cred.CredentialBlob = (LPVOID)password;
>         cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
> -       cred.AttributeCount = 1;
> -       cred.Attributes = attrs;
> +       cred.AttributeCount = 0;
> +       cred.Attributes = NULL;
>         cred.TargetAlias = NULL;
>         cred.UserName = wusername;
>
> -       write_attr(attrs, L"git_protocol", protocol);
> -
> -       if (host) {
> -               write_attr(attrs + cred.AttributeCount, L"git_host", host);
> -               cred.AttributeCount++;
> -       }
> -
> -       if (path) {
> -               write_attr(attrs + cred.AttributeCount, L"git_path", path);
> -               cred.AttributeCount++;
> -       }
> -
>         if (!CredWriteW(&cred, 0))
>                 die("CredWrite failed");
>  }

Nice.

> @@ -284,10 +211,13 @@ static void read_credential(void)
>
>         while (fgets(buf, sizeof(buf), stdin)) {
>                 char *v;
> +               int len = strlen(buf);
> +               /* strip trailing CR / LF */
> +               while (len && strchr("\r\n", buf[len - 1]))
> +                       buf[--len] = 0;
>
> -               if (!strcmp(buf, "\n"))
> +               if (!*buf)
>                         break;
> -               buf[strlen(buf)-1] = '\0';
>
>                 v = strchr(buf, '=');
>                 if (!v)

I think this part deserves a separate patch, no?

> @@ -295,13 +225,12 @@ static void read_credential(void)
>                 *v++ = '\0';
>
>                 if (!strcmp(buf, "protocol"))
> -                       protocol = xstrdup(v);
> +                       protocol = utf8_to_utf16_dup(v);
>                 else if (!strcmp(buf, "host"))
> -                       host = xstrdup(v);
> +                       host = utf8_to_utf16_dup(v);
>                 else if (!strcmp(buf, "path"))
> -                       path = xstrdup(v);
> +                       path = utf8_to_utf16_dup(v);
>                 else if (!strcmp(buf, "username")) {
> -                       username = xstrdup(v);
>                         wusername = utf8_to_utf16_dup(v);
>                 } else if (!strcmp(buf, "password"))
>                         password = utf8_to_utf16_dup(v);

So, you need the strings as UTF-16 instead so you can match against them...

> @@ -330,22 +259,20 @@ int main(int argc, char *argv[])
>                 return 0;
>
>         /* prepare 'target', the unique key for the credential */
> -       strncat(target_buf, "git:", sizeof(target_buf));
> -       strncat(target_buf, protocol, sizeof(target_buf));
> -       strncat(target_buf, "://", sizeof(target_buf));
> -       if (username) {
> -               strncat(target_buf, username, sizeof(target_buf));
> -               strncat(target_buf, "@", sizeof(target_buf));
> +       wcscpy(target, L"git:");
> +       wcsncat(target, protocol, ARRAY_SIZE(target));
> +       wcsncat(target, L"://", ARRAY_SIZE(target));
> +       if (wusername) {
> +               wcsncat(target, wusername, ARRAY_SIZE(target));
> +               wcsncat(target, L"@", ARRAY_SIZE(target));
>         }
>         if (host)
> -               strncat(target_buf, host, sizeof(target_buf));
> +               wcsncat(target, host, ARRAY_SIZE(target));
>         if (path) {
> -               strncat(target_buf, "/", sizeof(target_buf));
> -               strncat(target_buf, path, sizeof(target_buf));
> +               wcsncat(target, L"/", ARRAY_SIZE(target));
> +               wcsncat(target, path, ARRAY_SIZE(target));
>         }
>
> -       target = utf8_to_utf16_dup(target_buf);
> -

...Which means that you are composing a UTF-16 target directly rather
than ASCII. Looks sane.

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] wincred: improve compatibility with windows versions
  2013-01-04 21:57 ` Erik Faye-Lund
@ 2013-01-08 16:20   ` Karsten Blees
  2013-01-08 20:13     ` Erik Faye-Lund
  0 siblings, 1 reply; 15+ messages in thread
From: Karsten Blees @ 2013-01-08 16:20 UTC (permalink / raw)
  To: kusmabite; +Cc: git, msysgit, Jeff King

Am 04.01.2013 22:57, schrieb Erik Faye-Lund:
> On Fri, Jan 4, 2013 at 9:28 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
>> On WinXP, the windows credential helper doesn't work at all (due to missing
>> Cred[Un]PackAuthenticationBuffer APIs). On Win7, the credential format used
>> by wincred is incompatible with native Windows tools (such as the control
>> panel applet or 'cmdkey.exe /generic'). These Windows tools only set the
>> TargetName, UserName and CredentialBlob members of the CREDENTIAL
>> structure (where CredentialBlob is the UTF-16-encoded password).
>>
>> Remove the unnecessary packing / unpacking of the password, along with the
>> related API definitions, for compatibility with Windows XP.
>>
>> Don't use CREDENTIAL_ATTRIBUTEs to identify credentials for compatibility
>> with Windows credential manager tools. Parse the protocol, username, host
>> and path fields from the credential's target name instead.
>>
>> While we're at it, optionally accept CRLF (instead of LF only) to simplify
>> debugging in bash / cmd.
>>
>> Signed-off-by: Karsten Blees <blees@dcon.de>
>> ---
>>
>> Hi,
>>
>> I tried the windows credential helper yesterday and found that it doesn't work on XP at all, and doesn't work properly in combination with Win7 credential manager tools. So here's a patch that reduces it to the functionality provided / expected by Windows.
>>
>> @Erik, Jeff: Please let me know if I'm missing something and the use of Cred[Un]PackAuthenticationBuffer or CREDENTIAL_ATTRIBUTEs actually served a useful purpose.
>>
> 
> The only reason why I used Cred[Un]PackAuthenticationBuffer, were that
> I wasn't aware that it was possible any other way. I didn't even know
> there was a Windows Credential Manager in Windows XP.
> 

I believe the Cred* API was introduced in Win2k. The XP control panel applet supports domain credentials only, but cmdkey.exe from Windows Server 2003 can be used on XP to manage generic credentials.

> The credential attributes were because they were convenient, and I'm
> not sure I understand what you mean about the Win7 credential manager
> tools. I did test my code with it - in fact, it was a very useful tool
> for debugging the helper.
> 
> Are you referring to the credentials not *looking* like normal
> HTTP-credentials?

No, I was referring to creating / editing git credentials with Windows tools manually. For example, changing your password in control panel removes all credential attributes, so the current wincred won't find them any longer...same for git credentials created e.g. via 'cmdkey /generic:git:http://me@example.com /user:me /pass:secret'.

The 'puzzling' part is that those credentials *look* exactly the same as if created by wincred, but they don't work. And wincred isn't exactly verbose in its error messages :-)

> But, if we do any of these changes, does this mean I will lose my
> existing credentials? It's probably not a big deal, but it's worth a
> mention, isn't it?
> 

Yes, existing stored credentials are lost after this patch. Will add a note to the commit message.

We _could_ try to detect the old format, but I don't think it's worth the trouble.

>> @@ -67,20 +61,14 @@ typedef struct _CREDENTIALW {
>>  #define CRED_MAX_ATTRIBUTES 64
>>
>>  typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
>> -typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
>> -    LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
>>  typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
>>      PCREDENTIALW **);
>> -typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
>> -    PBYTE, DWORD *);
>>  typedef VOID (WINAPI *CredFreeT)(PVOID);
>>  typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
>>
>>  static HMODULE advapi, credui;
> 
> Perhaps get rid of credui also?
> 

Good catch

>>  static CredWriteWT CredWriteW;
>> -static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
>>  static CredEnumerateWT CredEnumerateW;
>> -static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
>>  static CredFreeT CredFree;
>>  static CredDeleteWT CredDeleteW;
>>
>> @@ -88,74 +76,64 @@ static void load_cred_funcs(void)
>>  {
>>         /* load DLLs */
>>         advapi = LoadLibrary("advapi32.dll");
>> -       credui = LoadLibrary("credui.dll");
>> -       if (!advapi || !credui)
>> +       if (!advapi)
>>                 die("failed to load DLLs");
> 
> It's not multiple DLLs any more, so perhaps "failed to load
> advapi32.dll" instead?
> 

Certainly

>> -static char target_buf[1024];
>> -static char *protocol, *host, *path, *username;
>> -static WCHAR *wusername, *password, *target;
>> +static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
>>
>> -static void write_item(const char *what, WCHAR *wbuf)
>> +static void write_item(const char *what, LPCWSTR wbuf, int wlen)
>>  {
>>         char *buf;
>> -       int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
>> +       int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
>>             FALSE);
>>         buf = xmalloc(len);
>>
>> -       if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
>> +       if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, buf, len, NULL, FALSE))
>>                 die("WideCharToMultiByte failed!");
>>
>>         printf("%s=", what);
>> -       fwrite(buf, 1, len - 1, stdout);
>> +       fwrite(buf, 1, len, stdout);
>>         putchar('\n');
>>         free(buf);
>>  }
>>
> 
> When the password-blob is simply UTF-16 encoded, are the
> zero-termination not included? That's the reason for this change,
> right?
> 

Yes, the Windows tools store the password without trailing \0.

>> -static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
>> -    const char *want)
>> +static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
>>  {
>> -       int i;
>> -       if (!want)
>> -               return 1;
>> -
>> -       for (i = 0; i < cred->AttributeCount; ++i)
>> -               if (!wcscmp(cred->Attributes[i].Keyword, keyword))
>> -                       return !strcmp((const char *)cred->Attributes[i].Value,
>> -                           want);
>> -
>> -       return 0; /* not found */
>> +       LPCWSTR start = *ptarget;
>> +       LPCWSTR end = *delim ? wcsstr(start, delim) : start + wcslen(start);
>> +       int len = end ? end - start : wcslen(start);
>> +       /* update ptarget if we either found a delimiter or need a match */
>> +       if (end || want)
>> +               *ptarget = end ? end + wcslen(delim) : start + len;
>> +       return !want || (!wcsncmp(want, start, len) && !want[len]);
>>  }
>>
> 
> I'm a bit tired now, but I'm having a hard time reading this code.
> Right now it seems it's a bit too ternary-expression heavy for my
> taste, though.
> 

OK, I'll flesh that out a bit. Perhaps a few more comments wouldn't hurt either.

>>  static int match_cred(const CREDENTIALW *cred)
>>  {
>> -       return (!wusername || !wcscmp(wusername, cred->UserName)) &&
>> -           match_attr(cred, L"git_protocol", protocol) &&
>> -           match_attr(cred, L"git_host", host) &&
>> -           match_attr(cred, L"git_path", path);
>> +       LPCWSTR target = cred->TargetName;
>> +       if (wusername && wcscmp(wusername, cred->UserName))
>> +               return 0;
>> +
>> +       return match_part(&target, L"git", L":") &&
>> +               match_part(&target, protocol, L"://") &&
>> +               match_part(&target, wusername, L"@") &&
>> +               match_part(&target, host, L"/") &&
>> +               match_part(&target, path, L"");
>>  }
>>
> 
> Ugh, it feels a bit wrong to store and verify the username twice. Do
> we really have to?
> 
> The target needs to be unique, even if two different usernames are
> stored for the same site under the same conditions. So probably. It
> just doesn't feel quite right.
> 

I don't really see why you would need several usernames to connect to the same target. I can imagine different credentials for reading / writing, but then the protocol would usually be different as well, wouldn't it? (e.g. http vs. ssh)

One of my interim solutions was to remove the username part from the URL entirely. That enabled me to change credentials in control panel (including the username), and wincred would use them. However, that version failed the 'helper can store multiple users' test, so I ended up with storing / checking username twice.

>> @@ -165,44 +143,15 @@ static void get_credential(void)
>>         /* search for the first credential that matches username */
>>         for (i = 0; i < num_creds; ++i)
>>                 if (match_cred(creds[i])) {
>> -                       cred = creds[i];
>> +                       write_item("username", creds[i]->UserName,
>> +                               wcslen(creds[i]->UserName));
>> +                       write_item("password",
>> +                               (LPCWSTR)creds[i]->CredentialBlob,
>> +                               creds[i]->CredentialBlobSize / sizeof(WCHAR));
>>                         break;
>>                 }
>> -       if (!cred)
>> -               return;
>> -
>> -       CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
>> -           cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
>> -           NULL, &pass_buf_size);
>> -
>> -       user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
>> -       pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
>> -
>> -       if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
>> -           cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
>> -           pass_buf, &pass_buf_size))
>> -               die("CredUnPackAuthenticationBuffer failed");
>>
>>         CredFree(creds);
>> -
>> -       /* zero-terminate (sizes include zero-termination) */
>> -       user_buf[user_buf_size - 1] = L'\0';
>> -       pass_buf[pass_buf_size - 1] = L'\0';
>> -
>> -       write_item("username", user_buf);
>> -       write_item("password", pass_buf);
>> -
>> -       free(user_buf);
>> -       free(pass_buf);
>> -}
> 
> Nice!
> 
>> -
>> -static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
>> -    const char *value)
>> -{
>> -       attr->Keyword = (LPWSTR)keyword;
>> -       attr->Flags = 0;
>> -       attr->ValueSize = strlen(value) + 1; /* store zero-termination */
>> -       attr->Value = (LPBYTE)value;
>>  }
>>
>>  static void store_credential(void)
>> @@ -215,40 +164,18 @@ static void store_credential(void)
>>         if (!wusername || !password)
>>                 return;
>>
>> -       /* query buffer size */
>> -       CredPackAuthenticationBufferW(0, wusername, password,
>> -           NULL, &auth_buf_size);
>> -
>> -       auth_buf = xmalloc(auth_buf_size);
>> -
>> -       if (!CredPackAuthenticationBufferW(0, wusername, password,
>> -           auth_buf, &auth_buf_size))
>> -               die("CredPackAuthenticationBuffer failed");
>> -
>>         cred.Flags = 0;
>>         cred.Type = CRED_TYPE_GENERIC;
>>         cred.TargetName = target;
>>         cred.Comment = L"saved by git-credential-wincred";
>> -       cred.CredentialBlobSize = auth_buf_size;
>> -       cred.CredentialBlob = auth_buf;
>> +       cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR);
>> +       cred.CredentialBlob = (LPVOID)password;
>>         cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
>> -       cred.AttributeCount = 1;
>> -       cred.Attributes = attrs;
>> +       cred.AttributeCount = 0;
>> +       cred.Attributes = NULL;
>>         cred.TargetAlias = NULL;
>>         cred.UserName = wusername;
>>
>> -       write_attr(attrs, L"git_protocol", protocol);
>> -
>> -       if (host) {
>> -               write_attr(attrs + cred.AttributeCount, L"git_host", host);
>> -               cred.AttributeCount++;
>> -       }
>> -
>> -       if (path) {
>> -               write_attr(attrs + cred.AttributeCount, L"git_path", path);
>> -               cred.AttributeCount++;
>> -       }
>> -
>>         if (!CredWriteW(&cred, 0))
>>                 die("CredWrite failed");
>>  }
> 
> Nice.
> 
>> @@ -284,10 +211,13 @@ static void read_credential(void)
>>
>>         while (fgets(buf, sizeof(buf), stdin)) {
>>                 char *v;
>> +               int len = strlen(buf);
>> +               /* strip trailing CR / LF */
>> +               while (len && strchr("\r\n", buf[len - 1]))
>> +                       buf[--len] = 0;
>>
>> -               if (!strcmp(buf, "\n"))
>> +               if (!*buf)
>>                         break;
>> -               buf[strlen(buf)-1] = '\0';
>>
>>                 v = strchr(buf, '=');
>>                 if (!v)
> 
> I think this part deserves a separate patch, no?
> 

Sigh...I thought I could get away without doing a patch series :-)

>> @@ -295,13 +225,12 @@ static void read_credential(void)
>>                 *v++ = '\0';
>>
>>                 if (!strcmp(buf, "protocol"))
>> -                       protocol = xstrdup(v);
>> +                       protocol = utf8_to_utf16_dup(v);
>>                 else if (!strcmp(buf, "host"))
>> -                       host = xstrdup(v);
>> +                       host = utf8_to_utf16_dup(v);
>>                 else if (!strcmp(buf, "path"))
>> -                       path = xstrdup(v);
>> +                       path = utf8_to_utf16_dup(v);
>>                 else if (!strcmp(buf, "username")) {
>> -                       username = xstrdup(v);
>>                         wusername = utf8_to_utf16_dup(v);
>>                 } else if (!strcmp(buf, "password"))
>>                         password = utf8_to_utf16_dup(v);
> 
> So, you need the strings as UTF-16 instead so you can match against them...
> 

Exactly

>> @@ -330,22 +259,20 @@ int main(int argc, char *argv[])
>>                 return 0;
>>
>>         /* prepare 'target', the unique key for the credential */
>> -       strncat(target_buf, "git:", sizeof(target_buf));
>> -       strncat(target_buf, protocol, sizeof(target_buf));
>> -       strncat(target_buf, "://", sizeof(target_buf));
>> -       if (username) {
>> -               strncat(target_buf, username, sizeof(target_buf));
>> -               strncat(target_buf, "@", sizeof(target_buf));
>> +       wcscpy(target, L"git:");
>> +       wcsncat(target, protocol, ARRAY_SIZE(target));
>> +       wcsncat(target, L"://", ARRAY_SIZE(target));
>> +       if (wusername) {
>> +               wcsncat(target, wusername, ARRAY_SIZE(target));
>> +               wcsncat(target, L"@", ARRAY_SIZE(target));
>>         }
>>         if (host)
>> -               strncat(target_buf, host, sizeof(target_buf));
>> +               wcsncat(target, host, ARRAY_SIZE(target));
>>         if (path) {
>> -               strncat(target_buf, "/", sizeof(target_buf));
>> -               strncat(target_buf, path, sizeof(target_buf));
>> +               wcsncat(target, L"/", ARRAY_SIZE(target));
>> +               wcsncat(target, path, ARRAY_SIZE(target));
>>         }
>>
>> -       target = utf8_to_utf16_dup(target_buf);
>> -
> 
> ...Which means that you are composing a UTF-16 target directly rather
> than ASCII. Looks sane.
> 

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] wincred: improve compatibility with windows versions
  2013-01-08 16:20   ` Karsten Blees
@ 2013-01-08 20:13     ` Erik Faye-Lund
  2013-01-10 12:10       ` [PATCH v2 0/2] improve-wincred-compatibility Karsten Blees
                         ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Erik Faye-Lund @ 2013-01-08 20:13 UTC (permalink / raw)
  To: blees; +Cc: git, msysgit, Jeff King

On Tue, Jan 8, 2013 at 5:20 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
> Am 04.01.2013 22:57, schrieb Erik Faye-Lund:
>> The only reason why I used Cred[Un]PackAuthenticationBuffer, were that
>> I wasn't aware that it was possible any other way. I didn't even know
>> there was a Windows Credential Manager in Windows XP.
>>
>
> I believe the Cred* API was introduced in Win2k. The XP control panel applet supports domain credentials only, but cmdkey.exe from Windows Server 2003 can be used on XP to manage generic credentials.
>

Thanks for the background-info.

>> The credential attributes were because they were convenient, and I'm
>> not sure I understand what you mean about the Win7 credential manager
>> tools. I did test my code with it - in fact, it was a very useful tool
>> for debugging the helper.
>>
>> Are you referring to the credentials not *looking* like normal
>> HTTP-credentials?
>
> No, I was referring to creating / editing git credentials with Windows tools manually. For example, changing your password in control panel removes all credential attributes, so the current wincred won't find them any longer...same for git credentials created e.g. via 'cmdkey /generic:git:http://me@example.com /user:me /pass:secret'.
>
> The 'puzzling' part is that those credentials *look* exactly the same as if created by wincred, but they don't work. And wincred isn't exactly verbose in its error messages :-)
>

Right, thanks for clearing that up.

>> But, if we do any of these changes, does this mean I will lose my
>> existing credentials? It's probably not a big deal, but it's worth a
>> mention, isn't it?
>>
>
> Yes, existing stored credentials are lost after this patch. Will add a note to the commit message.
>
> We _could_ try to detect the old format, but I don't think it's worth the trouble.
>

Nah, I don't think it's worth the trouble. It's a bit unfortunate that
people might get stale credentials clogging up the system, but I don't
really thing this is a big deal.

>>>  static int match_cred(const CREDENTIALW *cred)
>>>  {
>>> -       return (!wusername || !wcscmp(wusername, cred->UserName)) &&
>>> -           match_attr(cred, L"git_protocol", protocol) &&
>>> -           match_attr(cred, L"git_host", host) &&
>>> -           match_attr(cred, L"git_path", path);
>>> +       LPCWSTR target = cred->TargetName;
>>> +       if (wusername && wcscmp(wusername, cred->UserName))
>>> +               return 0;
>>> +
>>> +       return match_part(&target, L"git", L":") &&
>>> +               match_part(&target, protocol, L"://") &&
>>> +               match_part(&target, wusername, L"@") &&
>>> +               match_part(&target, host, L"/") &&
>>> +               match_part(&target, path, L"");
>>>  }
>>>
>>
>> Ugh, it feels a bit wrong to store and verify the username twice. Do
>> we really have to?
>>
>> The target needs to be unique, even if two different usernames are
>> stored for the same site under the same conditions. So probably. It
>> just doesn't feel quite right.
>>
>
> I don't really see why you would need several usernames to connect to the same target. I can imagine different credentials for reading / writing, but then the protocol would usually be different as well, wouldn't it? (e.g. http vs. ssh)
>

I can kind of make up some theoretical reasons, but they are a bit exotic ;)

> One of my interim solutions was to remove the username part from the URL entirely. That enabled me to change credentials in control panel (including the username), and wincred would use them. However, that version failed the 'helper can store multiple users' test, so I ended up with storing / checking username twice.
>

I don't think breaking this is a good idea. It just feels a bit silly,
but I see now that other applications does the same duplication. So
let's just stick to it, even if it's a bit icky ;)

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 0/2] improve-wincred-compatibility
  2013-01-08 20:13     ` Erik Faye-Lund
@ 2013-01-10 12:10       ` Karsten Blees
  2013-01-11 16:20         ` Erik Faye-Lund
  2013-01-10 12:10       ` [PATCH v2 1/2] wincred: accept CRLF on stdin to simplify console usage Karsten Blees
  2013-01-10 12:10       ` [PATCH v2 2/2] wincred: improve compatibility with windows versions Karsten Blees
  2 siblings, 1 reply; 15+ messages in thread
From: Karsten Blees @ 2013-01-10 12:10 UTC (permalink / raw)
  To: git; +Cc: kusmabite, msysgit, Jeff King

Changes since initial version (see attached diff for details):
- split in two patches
- removed unused variables
- improved the dll error message
- changed ?: to if else
- added comments

Also available here:
https://github.com/kblees/git/tree/kb/improve-wincred-compatibility-v2
git pull git://github.com/kblees/git.git kb/improve-wincred-compatibility-v2

Karsten Blees (2):
  wincred: accept CRLF on stdin to simplify console usage
  wincred: improve compatibility with windows versions

 .../credential/wincred/git-credential-wincred.c    | 206 ++++++++-------------
 1 file changed, 75 insertions(+), 131 deletions(-)


> git diff kb/improve-wincred-compatibility..kb/improve-wincred-compatibility-v2
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 3464080..dac19ea 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -66,7 +66,7 @@ typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
 typedef VOID (WINAPI *CredFreeT)(PVOID);
 typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
 
-static HMODULE advapi, credui;
+static HMODULE advapi;
 static CredWriteWT CredWriteW;
 static CredEnumerateWT CredEnumerateW;
 static CredFreeT CredFree;
@@ -77,7 +77,7 @@ static void load_cred_funcs(void)
 	/* load DLLs */
 	advapi = LoadLibrary("advapi32.dll");
 	if (!advapi)
-		die("failed to load DLLs");
+		die("failed to load advapi32.dll");
 
 	/* get function pointers */
 	CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
@@ -107,14 +107,34 @@ static void write_item(const char *what, LPCWSTR wbuf, int wlen)
 	free(buf);
 }
 
+/*
+ * Match an (optional) expected string and a delimiter in the target string,
+ * consuming the matched text by updating the target pointer.
+ */
 static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
 {
-	LPCWSTR start = *ptarget;
-	LPCWSTR end = *delim ? wcsstr(start, delim) : start + wcslen(start);
-	int len = end ? end - start : wcslen(start);
+	LPCWSTR delim_pos, start = *ptarget;
+	int len;
+
+	/* find start of delimiter (or end-of-string if delim is empty) */
+	if (*delim)
+		delim_pos = wcsstr(start, delim);
+	else
+		delim_pos = start + wcslen(start);
+
+	/*
+	 * match text up to delimiter, or end of string (e.g. the '/' after
+	 * host is optional if not followed by a path)
+	 */
+	if (delim_pos)
+		len = delim_pos - start;
+	else
+		len = wcslen(start);
+
 	/* update ptarget if we either found a delimiter or need a match */
-	if (end || want)
-		*ptarget = end ? end + wcslen(delim) : start + len;
+	if (delim_pos || want)
+		*ptarget = delim_pos ? delim_pos + wcslen(delim) : start + len;
+
 	return !want || (!wcsncmp(want, start, len) && !want[len]);
 }
 
@@ -157,9 +177,6 @@ static void get_credential(void)
 static void store_credential(void)
 {
 	CREDENTIALW cred;
-	BYTE *auth_buf;
-	DWORD auth_buf_size = 0;
-	CREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES];
 
 	if (!wusername || !password)
 		return;

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 1/2] wincred: accept CRLF on stdin to simplify console usage
  2013-01-08 20:13     ` Erik Faye-Lund
  2013-01-10 12:10       ` [PATCH v2 0/2] improve-wincred-compatibility Karsten Blees
@ 2013-01-10 12:10       ` Karsten Blees
  2013-01-10 12:10       ` [PATCH v2 2/2] wincred: improve compatibility with windows versions Karsten Blees
  2 siblings, 0 replies; 15+ messages in thread
From: Karsten Blees @ 2013-01-10 12:10 UTC (permalink / raw)
  To: git; +Cc: kusmabite, msysgit, Jeff King

The windows credential helper currently only accepts LF on stdin, but bash
and cmd.exe both send CRLF. This prevents interactive use in the console.

Change the stdin parser to optionally accept CRLF.

Signed-off-by: Karsten Blees <blees@dcon.de>
---
 contrib/credential/wincred/git-credential-wincred.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index cbaec5f..94d7140 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -284,10 +284,13 @@ static void read_credential(void)
 
 	while (fgets(buf, sizeof(buf), stdin)) {
 		char *v;
+		int len = strlen(buf);
+		/* strip trailing CR / LF */
+		while (len && strchr("\r\n", buf[len - 1]))
+			buf[--len] = 0;
 
-		if (!strcmp(buf, "\n"))
+		if (!*buf)
 			break;
-		buf[strlen(buf)-1] = '\0';
 
 		v = strchr(buf, '=');
 		if (!v)
-- 
1.8.0.msysgit.0.4.g4e40dea

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] wincred: improve compatibility with windows versions
  2013-01-08 20:13     ` Erik Faye-Lund
  2013-01-10 12:10       ` [PATCH v2 0/2] improve-wincred-compatibility Karsten Blees
  2013-01-10 12:10       ` [PATCH v2 1/2] wincred: accept CRLF on stdin to simplify console usage Karsten Blees
@ 2013-01-10 12:10       ` Karsten Blees
  2014-09-10 22:32         ` Erik Faye-Lund
  2 siblings, 1 reply; 15+ messages in thread
From: Karsten Blees @ 2013-01-10 12:10 UTC (permalink / raw)
  To: git; +Cc: kusmabite, msysgit, Jeff King

On WinXP, the windows credential helper doesn't work at all (due to missing
Cred[Un]PackAuthenticationBuffer APIs). On Win7, the credential format used
by wincred is incompatible with native Windows tools (such as the control
panel applet or 'cmdkey.exe /generic'). These Windows tools only set the
TargetName, UserName and CredentialBlob members of the CREDENTIAL
structure (where CredentialBlob is the UTF-16-encoded password).

Remove the unnecessary packing / unpacking of the password, along with the
related API definitions, for compatibility with Windows XP.

Don't use CREDENTIAL_ATTRIBUTEs to identify credentials for compatibility
with Windows credential manager tools. Parse the protocol, username, host
and path fields from the credential's target name instead.

Credentials created with an old wincred version will have mangled or empty
passwords after this change.

Signed-off-by: Karsten Blees <blees@dcon.de>
---
 .../credential/wincred/git-credential-wincred.c    | 199 ++++++++-------------
 1 file changed, 70 insertions(+), 129 deletions(-)

diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 94d7140..dac19ea 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -9,6 +9,8 @@
 
 /* common helpers */
 
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
 static void die(const char *err, ...)
 {
 	char msg[4096];
@@ -30,14 +32,6 @@ static void *xmalloc(size_t size)
 	return ret;
 }
 
-static char *xstrdup(const char *str)
-{
-	char *ret = strdup(str);
-	if (!ret)
-		die("Out of memory");
-	return ret;
-}
-
 /* MinGW doesn't have wincred.h, so we need to define stuff */
 
 typedef struct _CREDENTIAL_ATTRIBUTEW {
@@ -67,20 +61,14 @@ typedef struct _CREDENTIALW {
 #define CRED_MAX_ATTRIBUTES 64
 
 typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
-typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
-    LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
 typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
     PCREDENTIALW **);
-typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
-    PBYTE, DWORD *);
 typedef VOID (WINAPI *CredFreeT)(PVOID);
 typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
 
-static HMODULE advapi, credui;
+static HMODULE advapi;
 static CredWriteWT CredWriteW;
-static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
 static CredEnumerateWT CredEnumerateW;
-static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
 static CredFreeT CredFree;
 static CredDeleteWT CredDeleteW;
 
@@ -88,74 +76,84 @@ static void load_cred_funcs(void)
 {
 	/* load DLLs */
 	advapi = LoadLibrary("advapi32.dll");
-	credui = LoadLibrary("credui.dll");
-	if (!advapi || !credui)
-		die("failed to load DLLs");
+	if (!advapi)
+		die("failed to load advapi32.dll");
 
 	/* get function pointers */
 	CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
-	CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT)
-	    GetProcAddress(credui, "CredUnPackAuthenticationBufferW");
 	CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
 	    "CredEnumerateW");
-	CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT)
-	    GetProcAddress(credui, "CredPackAuthenticationBufferW");
 	CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
 	CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
-	if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
-	    !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
-	    !CredDeleteW)
+	if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW)
 		die("failed to load functions");
 }
 
-static char target_buf[1024];
-static char *protocol, *host, *path, *username;
-static WCHAR *wusername, *password, *target;
+static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
 
-static void write_item(const char *what, WCHAR *wbuf)
+static void write_item(const char *what, LPCWSTR wbuf, int wlen)
 {
 	char *buf;
-	int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
+	int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
 	    FALSE);
 	buf = xmalloc(len);
 
-	if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
+	if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, buf, len, NULL, FALSE))
 		die("WideCharToMultiByte failed!");
 
 	printf("%s=", what);
-	fwrite(buf, 1, len - 1, stdout);
+	fwrite(buf, 1, len, stdout);
 	putchar('\n');
 	free(buf);
 }
 
-static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
-    const char *want)
+/*
+ * Match an (optional) expected string and a delimiter in the target string,
+ * consuming the matched text by updating the target pointer.
+ */
+static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
 {
-	int i;
-	if (!want)
-		return 1;
-
-	for (i = 0; i < cred->AttributeCount; ++i)
-		if (!wcscmp(cred->Attributes[i].Keyword, keyword))
-			return !strcmp((const char *)cred->Attributes[i].Value,
-			    want);
-
-	return 0; /* not found */
+	LPCWSTR delim_pos, start = *ptarget;
+	int len;
+
+	/* find start of delimiter (or end-of-string if delim is empty) */
+	if (*delim)
+		delim_pos = wcsstr(start, delim);
+	else
+		delim_pos = start + wcslen(start);
+
+	/*
+	 * match text up to delimiter, or end of string (e.g. the '/' after
+	 * host is optional if not followed by a path)
+	 */
+	if (delim_pos)
+		len = delim_pos - start;
+	else
+		len = wcslen(start);
+
+	/* update ptarget if we either found a delimiter or need a match */
+	if (delim_pos || want)
+		*ptarget = delim_pos ? delim_pos + wcslen(delim) : start + len;
+
+	return !want || (!wcsncmp(want, start, len) && !want[len]);
 }
 
 static int match_cred(const CREDENTIALW *cred)
 {
-	return (!wusername || !wcscmp(wusername, cred->UserName)) &&
-	    match_attr(cred, L"git_protocol", protocol) &&
-	    match_attr(cred, L"git_host", host) &&
-	    match_attr(cred, L"git_path", path);
+	LPCWSTR target = cred->TargetName;
+	if (wusername && wcscmp(wusername, cred->UserName))
+		return 0;
+
+	return match_part(&target, L"git", L":") &&
+		match_part(&target, protocol, L"://") &&
+		match_part(&target, wusername, L"@") &&
+		match_part(&target, host, L"/") &&
+		match_part(&target, path, L"");
 }
 
 static void get_credential(void)
 {
-	WCHAR *user_buf, *pass_buf;
-	DWORD user_buf_size = 0, pass_buf_size = 0;
-	CREDENTIALW **creds, *cred = NULL;
+	CREDENTIALW **creds;
 	DWORD num_creds;
 	int i;
 
@@ -165,90 +163,36 @@ static void get_credential(void)
 	/* search for the first credential that matches username */
 	for (i = 0; i < num_creds; ++i)
 		if (match_cred(creds[i])) {
-			cred = creds[i];
+			write_item("username", creds[i]->UserName,
+				wcslen(creds[i]->UserName));
+			write_item("password",
+				(LPCWSTR)creds[i]->CredentialBlob,
+				creds[i]->CredentialBlobSize / sizeof(WCHAR));
 			break;
 		}
-	if (!cred)
-		return;
-
-	CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
-	    cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
-	    NULL, &pass_buf_size);
-
-	user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
-	pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
-
-	if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
-	    cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
-	    pass_buf, &pass_buf_size))
-		die("CredUnPackAuthenticationBuffer failed");
 
 	CredFree(creds);
-
-	/* zero-terminate (sizes include zero-termination) */
-	user_buf[user_buf_size - 1] = L'\0';
-	pass_buf[pass_buf_size - 1] = L'\0';
-
-	write_item("username", user_buf);
-	write_item("password", pass_buf);
-
-	free(user_buf);
-	free(pass_buf);
-}
-
-static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
-    const char *value)
-{
-	attr->Keyword = (LPWSTR)keyword;
-	attr->Flags = 0;
-	attr->ValueSize = strlen(value) + 1; /* store zero-termination */
-	attr->Value = (LPBYTE)value;
 }
 
 static void store_credential(void)
 {
 	CREDENTIALW cred;
-	BYTE *auth_buf;
-	DWORD auth_buf_size = 0;
-	CREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES];
 
 	if (!wusername || !password)
 		return;
 
-	/* query buffer size */
-	CredPackAuthenticationBufferW(0, wusername, password,
-	    NULL, &auth_buf_size);
-
-	auth_buf = xmalloc(auth_buf_size);
-
-	if (!CredPackAuthenticationBufferW(0, wusername, password,
-	    auth_buf, &auth_buf_size))
-		die("CredPackAuthenticationBuffer failed");
-
 	cred.Flags = 0;
 	cred.Type = CRED_TYPE_GENERIC;
 	cred.TargetName = target;
 	cred.Comment = L"saved by git-credential-wincred";
-	cred.CredentialBlobSize = auth_buf_size;
-	cred.CredentialBlob = auth_buf;
+	cred.CredentialBlobSize = (wcslen(password)) * sizeof(WCHAR);
+	cred.CredentialBlob = (LPVOID)password;
 	cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
-	cred.AttributeCount = 1;
-	cred.Attributes = attrs;
+	cred.AttributeCount = 0;
+	cred.Attributes = NULL;
 	cred.TargetAlias = NULL;
 	cred.UserName = wusername;
 
-	write_attr(attrs, L"git_protocol", protocol);
-
-	if (host) {
-		write_attr(attrs + cred.AttributeCount, L"git_host", host);
-		cred.AttributeCount++;
-	}
-
-	if (path) {
-		write_attr(attrs + cred.AttributeCount, L"git_path", path);
-		cred.AttributeCount++;
-	}
-
 	if (!CredWriteW(&cred, 0))
 		die("CredWrite failed");
 }
@@ -298,13 +242,12 @@ static void read_credential(void)
 		*v++ = '\0';
 
 		if (!strcmp(buf, "protocol"))
-			protocol = xstrdup(v);
+			protocol = utf8_to_utf16_dup(v);
 		else if (!strcmp(buf, "host"))
-			host = xstrdup(v);
+			host = utf8_to_utf16_dup(v);
 		else if (!strcmp(buf, "path"))
-			path = xstrdup(v);
+			path = utf8_to_utf16_dup(v);
 		else if (!strcmp(buf, "username")) {
-			username = xstrdup(v);
 			wusername = utf8_to_utf16_dup(v);
 		} else if (!strcmp(buf, "password"))
 			password = utf8_to_utf16_dup(v);
@@ -333,22 +276,20 @@ int main(int argc, char *argv[])
 		return 0;
 
 	/* prepare 'target', the unique key for the credential */
-	strncat(target_buf, "git:", sizeof(target_buf));
-	strncat(target_buf, protocol, sizeof(target_buf));
-	strncat(target_buf, "://", sizeof(target_buf));
-	if (username) {
-		strncat(target_buf, username, sizeof(target_buf));
-		strncat(target_buf, "@", sizeof(target_buf));
+	wcscpy(target, L"git:");
+	wcsncat(target, protocol, ARRAY_SIZE(target));
+	wcsncat(target, L"://", ARRAY_SIZE(target));
+	if (wusername) {
+		wcsncat(target, wusername, ARRAY_SIZE(target));
+		wcsncat(target, L"@", ARRAY_SIZE(target));
 	}
 	if (host)
-		strncat(target_buf, host, sizeof(target_buf));
+		wcsncat(target, host, ARRAY_SIZE(target));
 	if (path) {
-		strncat(target_buf, "/", sizeof(target_buf));
-		strncat(target_buf, path, sizeof(target_buf));
+		wcsncat(target, L"/", ARRAY_SIZE(target));
+		wcsncat(target, path, ARRAY_SIZE(target));
 	}
 
-	target = utf8_to_utf16_dup(target_buf);
-
 	if (!strcmp(argv[1], "get"))
 		get_credential();
 	else if (!strcmp(argv[1], "store"))
-- 
1.8.0.msysgit.0.4.g4e40dea

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-01-10 12:10       ` [PATCH v2 0/2] improve-wincred-compatibility Karsten Blees
@ 2013-01-11 16:20         ` Erik Faye-Lund
  2013-02-25  6:43           ` Junio C Hamano
  0 siblings, 1 reply; 15+ messages in thread
From: Erik Faye-Lund @ 2013-01-11 16:20 UTC (permalink / raw)
  To: blees; +Cc: git, msysgit, Jeff King

On Thu, Jan 10, 2013 at 1:10 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
> Changes since initial version (see attached diff for details):
> - split in two patches
> - removed unused variables
> - improved the dll error message
> - changed ?: to if else
> - added comments
>
> Also available here:
> https://github.com/kblees/git/tree/kb/improve-wincred-compatibility-v2
> git pull git://github.com/kblees/git.git kb/improve-wincred-compatibility-v2
>
> Karsten Blees (2):
>   wincred: accept CRLF on stdin to simplify console usage
>   wincred: improve compatibility with windows versions
>
>  .../credential/wincred/git-credential-wincred.c    | 206 ++++++++-------------
>  1 file changed, 75 insertions(+), 131 deletions(-)
>
>

Wonderful!

Acked-by: Erik Faye-Lund <kusmabite@gmail.com>

-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-01-11 16:20         ` Erik Faye-Lund
@ 2013-02-25  6:43           ` Junio C Hamano
  2013-02-25 23:39             ` Karsten Blees
  0 siblings, 1 reply; 15+ messages in thread
From: Junio C Hamano @ 2013-02-25  6:43 UTC (permalink / raw)
  To: kusmabite; +Cc: blees, git, msysgit, Jeff King

Erik Faye-Lund <kusmabite@gmail.com> writes:

> On Thu, Jan 10, 2013 at 1:10 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
>> Changes since initial version (see attached diff for details):
>> - split in two patches
>> - removed unused variables
>> - improved the dll error message
>> - changed ?: to if else
>> - added comments
>>
>> Also available here:
>> https://github.com/kblees/git/tree/kb/improve-wincred-compatibility-v2
>> git pull git://github.com/kblees/git.git kb/improve-wincred-compatibility-v2
>>
>> Karsten Blees (2):
>>   wincred: accept CRLF on stdin to simplify console usage
>>   wincred: improve compatibility with windows versions
>>
>>  .../credential/wincred/git-credential-wincred.c    | 206 ++++++++-------------
>>  1 file changed, 75 insertions(+), 131 deletions(-)
>>
>
> Wonderful!
>
> Acked-by: Erik Faye-Lund <kusmabite@gmail.com>

I'm in the "marking leftover bits" mode today, and noticed that
nothing happened for this topic in my tree. Did msysgit folks expect
me to pick this up directly, or did you guys want to feed this series
to me (with possibly other changes you worked on outside this list)?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-02-25  6:43           ` Junio C Hamano
@ 2013-02-25 23:39             ` Karsten Blees
  2013-02-25 23:51               ` Junio C Hamano
  2013-02-26 16:19               ` Johannes Schindelin
  0 siblings, 2 replies; 15+ messages in thread
From: Karsten Blees @ 2013-02-25 23:39 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: kusmabite, git, msysgit, Jeff King, patthoyts,
	Johannes.Schindelin

Am 25.02.2013 07:43, schrieb Junio C Hamano:
> Erik Faye-Lund <kusmabite@gmail.com> writes:
> 
>> On Thu, Jan 10, 2013 at 1:10 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
>>> Changes since initial version (see attached diff for details):
>>> - split in two patches
>>> - removed unused variables
>>> - improved the dll error message
>>> - changed ?: to if else
>>> - added comments
>>>
>>> Also available here:
>>> https://github.com/kblees/git/tree/kb/improve-wincred-compatibility-v2
>>> git pull git://github.com/kblees/git.git kb/improve-wincred-compatibility-v2
>>>
>>> Karsten Blees (2):
>>>   wincred: accept CRLF on stdin to simplify console usage
>>>   wincred: improve compatibility with windows versions
>>>
>>>  .../credential/wincred/git-credential-wincred.c    | 206 ++++++++-------------
>>>  1 file changed, 75 insertions(+), 131 deletions(-)
>>>
>>
>> Wonderful!
>>
>> Acked-by: Erik Faye-Lund <kusmabite@gmail.com>
> 
> I'm in the "marking leftover bits" mode today, and noticed that
> nothing happened for this topic in my tree. Did msysgit folks expect
> me to pick this up directly, or did you guys want to feed this series
> to me (with possibly other changes you worked on outside this list)?
> 

The second patch changes the credential format in a backward-incompatible way, so I think this should be in git.git, too (better than having two incompatible versions around).

@Pat, Dscho: the rebase-merge script should automatically drop patches found in upstream, correct?

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-02-25 23:39             ` Karsten Blees
@ 2013-02-25 23:51               ` Junio C Hamano
  2013-02-26 16:55                 ` Erik Faye-Lund
  2013-02-26 16:19               ` Johannes Schindelin
  1 sibling, 1 reply; 15+ messages in thread
From: Junio C Hamano @ 2013-02-25 23:51 UTC (permalink / raw)
  To: Karsten Blees
  Cc: kusmabite, git, msysgit, Jeff King, patthoyts,
	Johannes.Schindelin

Karsten Blees <karsten.blees@gmail.com> writes:

> Am 25.02.2013 07:43, schrieb Junio C Hamano:
>> Erik Faye-Lund <kusmabite@gmail.com> writes:
> ...
>> I'm in the "marking leftover bits" mode today, and noticed that
>> nothing happened for this topic in my tree. Did msysgit folks expect
>> me to pick this up directly, or did you guys want to feed this series
>> to me (with possibly other changes you worked on outside this list)?
>
> The second patch changes the credential format in a
> backward-incompatible way, so I think this should be in git.git,
> too (better than having two incompatible versions around).

I am a bit confused by that comment, as it was my understanding that
the "credential format" only refers to what is stored in the Windows
specific credential storage and relevant only to users of msysgit
(and I expected folks who are using Git natively on Windows to be
using msysgit, not git.git), but in any case, of course we would
want a single version and format.  My question was if msysgit folks
want me to take your patch (which I cannot test myself) and then
merge my tree to the msysgit tree as part of their regular updates
to catch up with 1.8.2 (and future releases), or they want to test
your patches in their tree first, and then either throw me a pull
request or send me a patch series with Acked-by:.

I can obviously go either way, but if they expect the former (i.e. I
first apply and they pull) while I expect the latter (i.e. they
first apply and I pull), then nothing will happen, and if we go the
other way around, we would end up getting two copies of the same
series. The question was primarily to avoid these possibilities.

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-02-25 23:39             ` Karsten Blees
  2013-02-25 23:51               ` Junio C Hamano
@ 2013-02-26 16:19               ` Johannes Schindelin
  1 sibling, 0 replies; 15+ messages in thread
From: Johannes Schindelin @ 2013-02-26 16:19 UTC (permalink / raw)
  To: Karsten Blees
  Cc: Junio C Hamano, kusmabite, git, msysgit, Jeff King, patthoyts

Hi Karsten,

On Tue, 26 Feb 2013, Karsten Blees wrote:

> @Pat, Dscho: the rebase-merge script should automatically drop patches
> found in upstream, correct?

Yep, that's the idea. Under some circumstances, --cherry will fail to pick
up on it and the commits will still be marked for 'pick', but when it
comes to them, there will be no changes to be committed.

Ciao,
Dscho

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-02-25 23:51               ` Junio C Hamano
@ 2013-02-26 16:55                 ` Erik Faye-Lund
  2013-02-26 17:29                   ` Junio C Hamano
  0 siblings, 1 reply; 15+ messages in thread
From: Erik Faye-Lund @ 2013-02-26 16:55 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Karsten Blees, git, msysgit, Jeff King, patthoyts,
	Johannes.Schindelin

On Tue, Feb 26, 2013 at 12:51 AM, Junio C Hamano <gitster@pobox.com> wrote:
> My question was if msysgit folks
> want me to take your patch (which I cannot test myself) and then
> merge my tree to the msysgit tree as part of their regular updates
> to catch up with 1.8.2 (and future releases), or they want to test
> your patches in their tree first, and then either throw me a pull
> request or send me a patch series with Acked-by:.

The following changes since commit 4dac0679feaebbf6545daec14480cf6b94cb74ed:

  Git 1.8.2-rc1 (2013-02-25 09:03:26 -0800)

are available in the git repository at:

  git://github.com/kusma/git.git for-junio

for you to fetch changes up to 8b2d219a3d6db49c8c3c0a5b620af33d6a40a974:

  wincred: improve compatibility with windows versions (2013-02-26
17:42:46 +0100)

----------------------------------------------------------------
Karsten Blees (2):
      wincred: accept CRLF on stdin to simplify console usage
      wincred: improve compatibility with windows versions

 .../credential/wincred/git-credential-wincred.c    | 206 ++++++++-------------
 1 file changed, 75 insertions(+), 131 deletions(-)

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 0/2] improve-wincred-compatibility
  2013-02-26 16:55                 ` Erik Faye-Lund
@ 2013-02-26 17:29                   ` Junio C Hamano
  0 siblings, 0 replies; 15+ messages in thread
From: Junio C Hamano @ 2013-02-26 17:29 UTC (permalink / raw)
  To: kusmabite
  Cc: Karsten Blees, git, msysgit, Jeff King, patthoyts,
	Johannes.Schindelin

Thanks.

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "msysGit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] wincred: improve compatibility with windows versions
  2013-01-10 12:10       ` [PATCH v2 2/2] wincred: improve compatibility with windows versions Karsten Blees
@ 2014-09-10 22:32         ` Erik Faye-Lund
  0 siblings, 0 replies; 15+ messages in thread
From: Erik Faye-Lund @ 2014-09-10 22:32 UTC (permalink / raw)
  To: Karsten Blees; +Cc: GIT Mailing-list, msysGit, Jeff King

On Thu, Jan 10, 2013 at 1:10 PM, Karsten Blees <karsten.blees@gmail.com> wrote:
>  static int match_cred(const CREDENTIALW *cred)
>  {
> -       return (!wusername || !wcscmp(wusername, cred->UserName)) &&
> -           match_attr(cred, L"git_protocol", protocol) &&
> -           match_attr(cred, L"git_host", host) &&
> -           match_attr(cred, L"git_path", path);
> +       LPCWSTR target = cred->TargetName;
> +       if (wusername && wcscmp(wusername, cred->UserName))
> +               return 0;
> +
> +       return match_part(&target, L"git", L":") &&
> +               match_part(&target, protocol, L"://") &&
> +               match_part(&target, wusername, L"@") &&

This seems to have broken credentials with '@' in the username, which
isn't all that unusual these days... :(

-- 
-- 
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.

You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en

--- 
You received this message because you are subscribed to the Google Groups "Git for Windows" group.
To unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2014-09-10 22:33 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-04 20:28 [PATCH] wincred: improve compatibility with windows versions Karsten Blees
2013-01-04 21:57 ` Erik Faye-Lund
2013-01-08 16:20   ` Karsten Blees
2013-01-08 20:13     ` Erik Faye-Lund
2013-01-10 12:10       ` [PATCH v2 0/2] improve-wincred-compatibility Karsten Blees
2013-01-11 16:20         ` Erik Faye-Lund
2013-02-25  6:43           ` Junio C Hamano
2013-02-25 23:39             ` Karsten Blees
2013-02-25 23:51               ` Junio C Hamano
2013-02-26 16:55                 ` Erik Faye-Lund
2013-02-26 17:29                   ` Junio C Hamano
2013-02-26 16:19               ` Johannes Schindelin
2013-01-10 12:10       ` [PATCH v2 1/2] wincred: accept CRLF on stdin to simplify console usage Karsten Blees
2013-01-10 12:10       ` [PATCH v2 2/2] wincred: improve compatibility with windows versions Karsten Blees
2014-09-10 22:32         ` Erik Faye-Lund

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).