{"thread":{"id":"30288","subject":"[PATCH v2] contrib: add win32 credential-helper","startedAt":"2012-04-19T18:45:22Z","lastAt":"2012-06-22T16:29:34Z","messageCount":6,"participants":["Erik Faye-Lund","Jeff King"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"189719","messageId":"1334861122-3144-1-git-send-email-kusmabite@gmail.com","threadId":"30288","inReplyTo":null,"subject":"[PATCH v2] contrib: add win32 credential-helper","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2012-04-19T18:45:22Z","receivedAt":"2012-04-19T18:45:22Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"Since the Windows port of Git expects binary pipes, we need to make\nsure the helper-end also sets up binary pipes.\n\nSide-step CRLF-issue in test to make it pass.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n\nHere's an updated version of my Windows credential-helper.\n\nThe most important difference is that it doesn't suck as much as\nit used to ;)\n\nBasically, I'm now using the attribute-system to store the meta-data\nfor the credentials.\n\nThis passes the test for me, and seems to work OK.\n\n contrib/credential/wincred/Makefile                |    8 +\n .../credential/wincred/git-credential-wincred.c    |  352 ++++++++++++++++++++\n t/lib-credential.sh                                |    4 +\n 3 files changed, 364 insertions(+), 0 deletions(-)\n create mode 100644 contrib/credential/wincred/Makefile\n create mode 100644 contrib/credential/wincred/git-credential-wincred.c\n\ndiff --git a/contrib/credential/wincred/Makefile b/contrib/credential/wincred/Makefile\nnew file mode 100644\nindex 0000000..b4f098f\n--- /dev/null\n+++ b/contrib/credential/wincred/Makefile\n@@ -0,0 +1,8 @@\n+all: git-credential-wincred.exe\n+\n+CC = gcc\n+RM = rm -f\n+CFLAGS = -O2 -Wall\n+\n+git-credential-wincred.exe : git-credential-wincred.c\n+\t$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@\ndiff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c\nnew file mode 100644\nindex 0000000..e63575f\n--- /dev/null\n+++ b/contrib/credential/wincred/git-credential-wincred.c\n@@ -0,0 +1,352 @@\n+/*\n+ * A git credential helper that interface with Windows' Credential Manager\n+ *\n+ */\n+#include <windows.h>\n+#include <stdio.h>\n+#include <io.h>\n+#include <fcntl.h>\n+\n+/* common helpers */\n+\n+static void die(const char *err, ...)\n+{\n+\tchar msg[4096];\n+\tva_list params;\n+\tva_start(params, err);\n+\tvsnprintf(msg, sizeof(msg), err, params);\n+\tfprintf(stderr, \"%s\\n\", msg);\n+\tva_end(params);\n+\texit(1);\n+}\n+\n+static void *xmalloc(size_t size)\n+{\n+\tvoid *ret = malloc(size);\n+\tif (!ret && !size)\n+\t\tret = malloc(1);\n+\tif (!ret)\n+\t\t die(\"Out of memory\");\n+\treturn ret;\n+}\n+\n+static char *xstrdup(const char *str)\n+{\n+\tchar *ret = strdup(str);\n+\tif (!ret)\n+\t\tdie(\"Out of memory\");\n+\treturn ret;\n+}\n+\n+/* MinGW doesn't have wincred.h, so we need to define stuff */\n+\n+typedef struct _CREDENTIAL_ATTRIBUTEW {\n+\tLPWSTR Keyword;\n+\tDWORD  Flags;\n+\tDWORD  ValueSize;\n+\tLPBYTE Value;\n+} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;\n+\n+typedef struct _CREDENTIALW {\n+\tDWORD                  Flags;\n+\tDWORD                  Type;\n+\tLPWSTR                 TargetName;\n+\tLPWSTR                 Comment;\n+\tFILETIME               LastWritten;\n+\tDWORD                  CredentialBlobSize;\n+\tLPBYTE                 CredentialBlob;\n+\tDWORD                  Persist;\n+\tDWORD                  AttributeCount;\n+\tPCREDENTIAL_ATTRIBUTEW Attributes;\n+\tLPWSTR                 TargetAlias;\n+\tLPWSTR                 UserName;\n+} CREDENTIALW, *PCREDENTIALW;\n+\n+#define CRED_TYPE_GENERIC 1\n+#define CRED_PERSIST_LOCAL_MACHINE 2\n+#define CRED_MAX_ATTRIBUTES 64\n+\n+typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);\n+typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,\n+    LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);\n+typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,\n+    PCREDENTIALW **);\n+typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,\n+    PBYTE, DWORD *);\n+typedef VOID (WINAPI *CredFreeT)(PVOID);\n+typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);\n+\n+static HMODULE advapi, credui;\n+static CredWriteWT CredWriteW;\n+static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;\n+static CredEnumerateWT CredEnumerateW;\n+static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;\n+static CredFreeT CredFree;\n+static CredDeleteWT CredDeleteW;\n+\n+static void load_cred_funcs(void)\n+{\n+\t/* load DLLs */\n+\tadvapi = LoadLibrary(\"advapi32.dll\");\n+\tcredui = LoadLibrary(\"credui.dll\");\n+\tif (!advapi || !credui)\n+\t\tdie(\"failed to load DLLs\");\n+\n+\t/* get function pointers */\n+\tCredWriteW = (CredWriteWT)GetProcAddress(advapi, \"CredWriteW\");\n+\tCredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT)\n+\t    GetProcAddress(credui, \"CredUnPackAuthenticationBufferW\");\n+\tCredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,\n+\t    \"CredEnumerateW\");\n+\tCredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT)\n+\t    GetProcAddress(credui, \"CredPackAuthenticationBufferW\");\n+\tCredFree = (CredFreeT)GetProcAddress(advapi, \"CredFree\");\n+\tCredDeleteW = (CredDeleteWT)GetProcAddress(advapi, \"CredDeleteW\");\n+\tif (!CredWriteW || !CredUnPackAuthenticationBufferW ||\n+\t    !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||\n+\t    !CredDeleteW)\n+\t\tdie(\"failed to load functions\");\n+}\n+\n+static char target_buf[1024];\n+static char *protocol, *host, *path, *username;\n+static WCHAR *wusername, *password, *target;\n+\n+static void write_item(const char *what, WCHAR *wbuf)\n+{\n+\tchar *buf;\n+\tint len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,\n+\t    FALSE);\n+\tbuf = xmalloc(len);\n+\n+\tif (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))\n+\t\tdie(\"WideCharToMultiByte failed!\");\n+\n+\tprintf(\"%s=\", what);\n+\tfwrite(buf, 1, len - 1, stdout);\n+\tputchar('\\n');\n+\tfree(buf);\n+}\n+\n+static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,\n+    const char *want)\n+{\n+\tint i;\n+\tif (!want)\n+\t\treturn 1;\n+\n+\tfor (i = 0; i < cred->AttributeCount; ++i)\n+\t\tif (!wcscmp(cred->Attributes[i].Keyword, keyword))\n+\t\t\treturn !strcmp((const char *)cred->Attributes[i].Value,\n+\t\t\t    want);\n+\n+\treturn 0; /* not found */\n+}\n+\n+static int match_cred(const CREDENTIALW *cred)\n+{\n+\treturn (!wusername || !wcscmp(wusername, cred->UserName)) &&\n+\t    match_attr(cred, L\"git_protocol\", protocol) &&\n+\t    match_attr(cred, L\"git_host\", host) &&\n+\t    match_attr(cred, L\"git_path\", path);\n+}\n+\n+static void get_credential(void)\n+{\n+\tWCHAR *user_buf, *pass_buf;\n+\tDWORD user_buf_size = 0, pass_buf_size = 0;\n+\tCREDENTIALW **creds, *cred = NULL;\n+\tDWORD num_creds;\n+\tint i;\n+\n+\tif (!CredEnumerateW(L\"git:*\", 0, &num_creds, &creds))\n+\t\treturn;\n+\n+\t/* search for the first credential that matches username */\n+\tfor (i = 0; i < num_creds; ++i)\n+\t\tif (match_cred(creds[i])) {\n+\t\t\tcred = creds[i];\n+\t\t\tbreak;\n+\t\t}\n+\tif (!cred)\n+\t\treturn;\n+\n+\tCredUnPackAuthenticationBufferW(0, cred->CredentialBlob,\n+\t    cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,\n+\t    NULL, &pass_buf_size);\n+\n+\tuser_buf = xmalloc(user_buf_size * sizeof(WCHAR));\n+\tpass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));\n+\n+\tif (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,\n+\t    cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,\n+\t    pass_buf, &pass_buf_size))\n+\t\tdie(\"CredUnPackAuthenticationBuffer failed\");\n+\n+\tCredFree(creds);\n+\n+\t/* zero-terminate (sizes include zero-termination) */\n+\tuser_buf[user_buf_size - 1] = L'\\0';\n+\tpass_buf[pass_buf_size - 1] = L'\\0';\n+\n+\twrite_item(\"username\", user_buf);\n+\twrite_item(\"password\", pass_buf);\n+\n+\tfree(user_buf);\n+\tfree(pass_buf);\n+}\n+\n+static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,\n+    const char *value)\n+{\n+\tattr->Keyword = (LPWSTR)keyword;\n+\tattr->Flags = 0;\n+\tattr->ValueSize = strlen(value) + 1; /* store zero-termination */\n+\tattr->Value = (LPBYTE)value;\n+}\n+\n+static void store_credential(void)\n+{\n+\tCREDENTIALW cred;\n+\tBYTE *auth_buf;\n+\tDWORD auth_buf_size = 0;\n+\tCREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES];\n+\n+\tif (!wusername || !password)\n+\t\treturn;\n+\n+\t/* query buffer size */\n+\tCredPackAuthenticationBufferW(0, wusername, password,\n+\t    NULL, &auth_buf_size);\n+\n+\tauth_buf = xmalloc(auth_buf_size);\n+\n+\tif (!CredPackAuthenticationBufferW(0, wusername, password,\n+\t    auth_buf, &auth_buf_size))\n+\t\tdie(\"CredPackAuthenticationBuffer failed\");\n+\n+\tcred.Flags = 0;\n+\tcred.Type = CRED_TYPE_GENERIC;\n+\tcred.TargetName = target;\n+\tcred.Comment = L\"saved by git-credential-wincred\";\n+\tcred.CredentialBlobSize = auth_buf_size;\n+\tcred.CredentialBlob = auth_buf;\n+\tcred.Persist = CRED_PERSIST_LOCAL_MACHINE;\n+\tcred.AttributeCount = 2;\n+\tcred.Attributes = attrs;\n+\tcred.TargetAlias = NULL;\n+\tcred.UserName = wusername;\n+\n+\twrite_attr(attrs, L\"git_protocol\", protocol);\n+\twrite_attr(attrs + 1, L\"git_host\", host);\n+\n+\tif (path) {\n+\t\twrite_attr(attrs + 2, L\"git_path\", path);\n+\t\tcred.AttributeCount++;\n+\t}\n+\n+\tif (!CredWriteW(&cred, 0))\n+\t\tdie(\"CredWrite failed\");\n+}\n+\n+static void erase_credential(void)\n+{\n+\tCREDENTIALW **creds;\n+\tDWORD num_creds;\n+\tint i;\n+\n+\tif (!CredEnumerateW(L\"git:*\", 0, &num_creds, &creds))\n+\t\treturn;\n+\n+\tfor (i = 0; i < num_creds; ++i) {\n+\t\tif (match_cred(creds[i]))\n+\t\t\tCredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);\n+\t}\n+\n+\tCredFree(creds);\n+}\n+\n+static WCHAR *utf8_to_utf16_dup(const char *str)\n+{\n+\tint wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);\n+\tWCHAR *wstr = xmalloc(sizeof(WCHAR) * wlen);\n+\tMultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, wlen);\n+\treturn wstr;\n+}\n+\n+static void read_credential(void)\n+{\n+\tchar buf[1024];\n+\n+\twhile (fgets(buf, sizeof(buf), stdin)) {\n+\t\tchar *v;\n+\n+\t\tif (!strcmp(buf, \"\\n\"))\n+\t\t\tbreak;\n+\t\tbuf[strlen(buf)-1] = '\\0';\n+\n+\t\tv = strchr(buf, '=');\n+\t\tif (!v)\n+\t\t\tdie(\"bad input: %s\", buf);\n+\t\t*v++ = '\\0';\n+\n+\t\tif (!strcmp(buf, \"protocol\"))\n+\t\t\tprotocol = xstrdup(v);\n+\t\telse if (!strcmp(buf, \"host\"))\n+\t\t\thost = xstrdup(v);\n+\t\telse if (!strcmp(buf, \"path\"))\n+\t\t\tpath = xstrdup(v);\n+\t\telse if (!strcmp(buf, \"username\")) {\n+\t\t\tusername = xstrdup(v);\n+\t\t\twusername = utf8_to_utf16_dup(v);\n+\t\t} else if (!strcmp(buf, \"password\"))\n+\t\t\tpassword = utf8_to_utf16_dup(v);\n+\t\telse\n+\t\t\tdie(\"unrecognized input\");\n+\t}\n+}\n+\n+int main(int argc, char *argv[])\n+{\n+\tconst char *usage =\n+\t    \"Usage: git credential-wincred <get|store|erase>\\n\";\n+\n+\tif (!argv[1])\n+\t\tdie(usage);\n+\n+\t/* git use binary pipes to avoid CRLF-issues */\n+\t_setmode(_fileno(stdin), _O_BINARY);\n+\t_setmode(_fileno(stdout), _O_BINARY);\n+\n+\tread_credential();\n+\n+\tload_cred_funcs();\n+\n+\tif (!protocol || !host)\n+\t\treturn 0;\n+\n+\t/* prepare 'target', the unique key for the credential */\n+\tstrncat(target_buf, \"git:\", sizeof(target_buf));\n+\tstrncat(target_buf, protocol, sizeof(target_buf));\n+\tstrncat(target_buf, \"://\", sizeof(target_buf));\n+\tif (username) {\n+\t\tstrncat(target_buf, username, sizeof(target_buf));\n+\t\tstrncat(target_buf, \"@\", sizeof(target_buf));\n+\t}\n+\tstrncat(target_buf, host, sizeof(target_buf));\n+\tif (path) {\n+\t\tstrncat(target_buf, \"/\", sizeof(target_buf));\n+\t\tstrncat(target_buf, path, sizeof(target_buf));\n+\t}\n+\n+\ttarget = utf8_to_utf16_dup(target_buf);\n+\n+\tif (!strcmp(argv[1], \"get\"))\n+\t\tget_credential();\n+\telse if (!strcmp(argv[1], \"store\"))\n+\t\tstore_credential();\n+\telse if (!strcmp(argv[1], \"erase\"))\n+\t\terase_credential();\n+\t/* otherwise, ignore unknown action */\n+\treturn 0;\n+}\ndiff --git a/t/lib-credential.sh b/t/lib-credential.sh\nindex 4a37cd7..d30ae8a 100755\n--- a/t/lib-credential.sh\n+++ b/t/lib-credential.sh\n@@ -8,6 +8,10 @@ check() {\n \tread_chunk >expect-stdout &&\n \tread_chunk >expect-stderr &&\n \ttest-credential \"$@\" <stdin >stdout 2>stderr &&\n+\tif test_have_prereq MINGW\n+\tthen\n+\t\tdos2unix -q stderr\n+\tfi &&\n \ttest_cmp expect-stdout stdout &&\n \ttest_cmp expect-stderr stderr\n }\n-- \n1.7.9\n\n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n\n*** Please avoid top-posting. ***\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n"},{"id":"189839","messageId":"20120422180716.GA27339@sigill.intra.peff.net","threadId":"30288","inReplyTo":"1334861122-3144-1-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH v2] contrib: add win32 credential-helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-22T18:07:17Z","receivedAt":"2012-04-22T18:07:17Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 19, 2012 at 08:45:22PM +0200, Erik Faye-Lund wrote:\n\n> Here's an updated version of my Windows credential-helper.\n\nSorry, I've been traveling and haven't had a chance to look at this\nin-depth yet. I'll do so next week. In the meantime, I wanted to point\nout this similar project:\n\n  https://github.com/anurse/git-credential-winstore\n\nwhich somebody else pointed me to a few days ago. I don't know yet if\nyour approaches are the same, or if it would be worth combining efforts\nor not.\n\n-Peff\n\n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n\n*** Please avoid top-posting. ***\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n"},{"id":"189884","messageId":"CABPQNSawsoheM6Qoxs-iQ-KYxYFs-s60oFLzdyRDFT0o=KXt1w@mail.gmail.com","threadId":"30288","inReplyTo":"20120422180716.GA27339@sigill.intra.peff.net","subject":"Re: [PATCH v2] contrib: add win32 credential-helper","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2012-04-23T16:05:57Z","receivedAt":"2012-04-23T16:05:57Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Sun, Apr 22, 2012 at 8:07 PM, Jeff King <peff@peff.net> wrote:\n> On Thu, Apr 19, 2012 at 08:45:22PM +0200, Erik Faye-Lund wrote:\n>\n>> Here's an updated version of my Windows credential-helper.\n>\n> Sorry, I've been traveling and haven't had a chance to look at this\n> in-depth yet. I'll do so next week. In the meantime, I wanted to point\n> out this similar project:\n>\n>  https://github.com/anurse/git-credential-winstore\n>\n> which somebody else pointed me to a few days ago. I don't know yet if\n> your approaches are the same, or if it would be worth combining efforts\n> or not.\n\nYeah, I saw that one a couple of days ago myself.\n\nThey use the same credential store, and I actually tried to make sure\nthey can use the same data.\n\nBut apart from that, they work quite differently. My credential-helper\nonly does storage, and passes the test-suite. The one you linked to\nseems to ignore any password being sent to it, and instead prompts the\nuser if it doesn't already have a credential. It also does not seem to\nsupport storing credentials for multiple users for a domain/path.\n\nBut probably the biggest problem for Git for Windows is that it's\nwritten in C#, and we don't have a C# compiler in our tool-chain.\n\nSo I don't think there's much I can use from that helper, and I think\nmy helper is in a healthier state. But I'm obviously biased.\n\n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n\n*** Please avoid top-posting. ***\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n"},{"id":"189992","messageId":"20120424202108.GB21904@sigill.intra.peff.net","threadId":"30288","inReplyTo":"CABPQNSawsoheM6Qoxs-iQ-KYxYFs-s60oFLzdyRDFT0o=KXt1w@mail.gmail.com","subject":"Re: [PATCH v2] contrib: add win32 credential-helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-24T20:21:08Z","receivedAt":"2012-04-24T20:21:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 23, 2012 at 06:05:57PM +0200, Erik Faye-Lund wrote:\n\n> > Sorry, I've been traveling and haven't had a chance to look at this\n> > in-depth yet. I'll do so next week. In the meantime, I wanted to point\n> > out this similar project:\n> >\n> >  https://github.com/anurse/git-credential-winstore\n> [...]\n> But probably the biggest problem for Git for Windows is that it's\n> written in C#, and we don't have a C# compiler in our tool-chain.\n\nYeah, that seems like a big one. I think it would be awesome if msysgit\ncould eventually ship with a credential helper, without people needing\nto grab something externally.\n\n-Peff\n\n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n\n*** Please avoid top-posting. ***\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n"},{"id":"189994","messageId":"20120424204052.GC21904@sigill.intra.peff.net","threadId":"30288","inReplyTo":"1334861122-3144-1-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH v2] contrib: add win32 credential-helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-24T20:40:52Z","receivedAt":"2012-04-24T20:40:52Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 19, 2012 at 08:45:22PM +0200, Erik Faye-Lund wrote:\n\n> Here's an updated version of my Windows credential-helper.\n> \n> The most important difference is that it doesn't suck as much as\n> it used to ;)\n> \n> Basically, I'm now using the attribute-system to store the meta-data\n> for the credentials.\n> \n> This passes the test for me, and seems to work OK.\n\nThis looks much better. As usual, I can't comment on the Windows-y\nparts, but the credential logic looks good. One minor comment:\n\n> +int main(int argc, char *argv[])\n> +{\n> [...]\n> +\tif (!protocol || !host)\n> +\t\treturn 0;\n\nYou could have a protocol that does not have a \"host\" component. Git\nwill produce this for a cached certificate password (which will then\nalways have a \"path\" field). I don't know if anybody is using it to\ncache certificate passwords, and I admit that it is not very well tested\nby me, either. So I'm not sure anybody will actually care.\n\nThe credential-store helper uses this logic:\n\n  $ sed -n '70,79p' credential-store.c\n        /*\n         * Sanity check that what we are storing is actually sensible.\n         * In particular, we can't make a URL without a protocol field.\n         * Without either a host or pathname (depending on the scheme),\n         * we have no primary key. And without a username and password,\n         * we are not actually storing a credential.\n         */\n        if (!c->protocol || !(c->host || c->path) ||\n            !c->username || !c->password)\n                return;\n\nI'm pretty sure the OS X helper does not handle certificate passwords at\nall. It is harder there, because I map directly to native protocol\ntypes, and I haven't checked to see whether OS X handles this type. But\nsince you are just storing whatever protocol information git hands you,\nI think for you it is just a matter of letting it through (and handling\nthe \"!host\" case when writing).\n\n-Peff\n\n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n\n*** Please avoid top-posting. ***\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n"},{"id":"194078","messageId":"CABPQNSZLVuDKi0k0fhW+WyvCG_ShDETt_0i+BnmDUUE_su9Suw@mail.gmail.com","threadId":"30288","inReplyTo":"20120424204052.GC21904@sigill.intra.peff.net","subject":"Re: [PATCH v2] contrib: add win32 credential-helper","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2012-06-22T16:29:34Z","receivedAt":"2012-06-22T16:29:34Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Apr 24, 2012 at 10:40 PM, Jeff King <peff@peff.net> wrote:\n> On Thu, Apr 19, 2012 at 08:45:22PM +0200, Erik Faye-Lund wrote:\n>\n>> Here's an updated version of my Windows credential-helper.\n>>\n>> The most important difference is that it doesn't suck as much as\n>> it used to ;)\n>>\n>> Basically, I'm now using the attribute-system to store the meta-data\n>> for the credentials.\n>>\n>> This passes the test for me, and seems to work OK.\n>\n> This looks much better. As usual, I can't comment on the Windows-y\n> parts, but the credential logic looks good. One minor comment:\n>\n>> +int main(int argc, char *argv[])\n>> +{\n>> [...]\n>> +     if (!protocol || !host)\n>> +             return 0;\n>\n> You could have a protocol that does not have a \"host\" component. Git\n> will produce this for a cached certificate password (which will then\n> always have a \"path\" field). I don't know if anybody is using it to\n> cache certificate passwords, and I admit that it is not very well tested\n> by me, either. So I'm not sure anybody will actually care.\n>\n> The credential-store helper uses this logic:\n>\n>  $ sed -n '70,79p' credential-store.c\n>        /*\n>         * Sanity check that what we are storing is actually sensible.\n>         * In particular, we can't make a URL without a protocol field.\n>         * Without either a host or pathname (depending on the scheme),\n>         * we have no primary key. And without a username and password,\n>         * we are not actually storing a credential.\n>         */\n>        if (!c->protocol || !(c->host || c->path) ||\n>            !c->username || !c->password)\n>                return;\n>\n> I'm pretty sure the OS X helper does not handle certificate passwords at\n> all. It is harder there, because I map directly to native protocol\n> types, and I haven't checked to see whether OS X handles this type.\n\nRight. I copied this logic from the OSX helper.\n\n> But\n> since you are just storing whatever protocol information git hands you,\n> I think for you it is just a matter of letting it through (and handling\n> the \"!host\" case when writing).\n\nYeah, I agree. This on top should do it:\n\ndiff --git a/contrib/credential/wincred/git-credential-wincred.c\nb/contrib/credential/wincred/git-credential-wincred.c\nindex e63575f..cbaec5f 100644\n--- a/contrib/credential/wincred/git-credential-wincred.c\n+++ b/contrib/credential/wincred/git-credential-wincred.c\n@@ -232,16 +232,20 @@ static void store_credential(void)\n \tcred.CredentialBlobSize = auth_buf_size;\n \tcred.CredentialBlob = auth_buf;\n \tcred.Persist = CRED_PERSIST_LOCAL_MACHINE;\n-\tcred.AttributeCount = 2;\n+\tcred.AttributeCount = 1;\n \tcred.Attributes = attrs;\n \tcred.TargetAlias = NULL;\n \tcred.UserName = wusername;\n\n \twrite_attr(attrs, L\"git_protocol\", protocol);\n-\twrite_attr(attrs + 1, L\"git_host\", host);\n+\n+\tif (host) {\n+\t\twrite_attr(attrs + cred.AttributeCount, L\"git_host\", host);\n+\t\tcred.AttributeCount++;\n+\t}\n\n \tif (path) {\n-\t\twrite_attr(attrs + 2, L\"git_path\", path);\n+\t\twrite_attr(attrs + cred.AttributeCount, L\"git_path\", path);\n \t\tcred.AttributeCount++;\n \t}\n\n@@ -322,7 +326,7 @@ int main(int argc, char *argv[])\n\n \tload_cred_funcs();\n\n-\tif (!protocol || !host)\n+\tif (!protocol || !(host || path))\n \t\treturn 0;\n\n \t/* prepare 'target', the unique key for the credential */\n@@ -333,7 +337,8 @@ int main(int argc, char *argv[])\n \t\tstrncat(target_buf, username, sizeof(target_buf));\n \t\tstrncat(target_buf, \"@\", sizeof(target_buf));\n \t}\n-\tstrncat(target_buf, host, sizeof(target_buf));\n+\tif (host)\n+\t\tstrncat(target_buf, host, sizeof(target_buf));\n \tif (path) {\n \t\tstrncat(target_buf, \"/\", sizeof(target_buf));\n \t\tstrncat(target_buf, path, sizeof(target_buf));\n\n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n*** Please avoid top-posting. ***\nThe msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, and view previous threads, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n"}]}