99
1010/* common helpers */
1111
12+ #define ARRAY_SIZE (x ) (sizeof(x)/sizeof(x[0]))
13+
1214static void die (const char * err , ...)
1315{
1416 char msg [4096 ];
@@ -30,14 +32,6 @@ static void *xmalloc(size_t size)
3032 return ret ;
3133}
3234
33- static char * xstrdup (const char * str )
34- {
35- char * ret = strdup (str );
36- if (!ret )
37- die ("Out of memory" );
38- return ret ;
39- }
40-
4135/* MinGW doesn't have wincred.h, so we need to define stuff */
4236
4337typedef struct _CREDENTIAL_ATTRIBUTEW {
@@ -67,95 +61,99 @@ typedef struct _CREDENTIALW {
6761#define CRED_MAX_ATTRIBUTES 64
6862
6963typedef BOOL (WINAPI * CredWriteWT )(PCREDENTIALW , DWORD );
70- typedef BOOL (WINAPI * CredUnPackAuthenticationBufferWT )(DWORD , PVOID , DWORD ,
71- LPWSTR , DWORD * , LPWSTR , DWORD * , LPWSTR , DWORD * );
7264typedef BOOL (WINAPI * CredEnumerateWT )(LPCWSTR , DWORD , DWORD * ,
7365 PCREDENTIALW * * );
74- typedef BOOL (WINAPI * CredPackAuthenticationBufferWT )(DWORD , LPWSTR , LPWSTR ,
75- PBYTE , DWORD * );
7666typedef VOID (WINAPI * CredFreeT )(PVOID );
7767typedef BOOL (WINAPI * CredDeleteWT )(LPCWSTR , DWORD , DWORD );
7868
79- static HMODULE advapi , credui ;
69+ static HMODULE advapi ;
8070static CredWriteWT CredWriteW ;
81- static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW ;
8271static CredEnumerateWT CredEnumerateW ;
83- static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW ;
8472static CredFreeT CredFree ;
8573static CredDeleteWT CredDeleteW ;
8674
8775static void load_cred_funcs (void )
8876{
8977 /* load DLLs */
9078 advapi = LoadLibrary ("advapi32.dll" );
91- credui = LoadLibrary ("credui.dll" );
92- if (!advapi || !credui )
93- die ("failed to load DLLs" );
79+ if (!advapi )
80+ die ("failed to load advapi32.dll" );
9481
9582 /* get function pointers */
9683 CredWriteW = (CredWriteWT )GetProcAddress (advapi , "CredWriteW" );
97- CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT )
98- GetProcAddress (credui , "CredUnPackAuthenticationBufferW" );
9984 CredEnumerateW = (CredEnumerateWT )GetProcAddress (advapi ,
10085 "CredEnumerateW" );
101- CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT )
102- GetProcAddress (credui , "CredPackAuthenticationBufferW" );
10386 CredFree = (CredFreeT )GetProcAddress (advapi , "CredFree" );
10487 CredDeleteW = (CredDeleteWT )GetProcAddress (advapi , "CredDeleteW" );
105- if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
106- !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
107- !CredDeleteW )
88+ if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW )
10889 die ("failed to load functions" );
10990}
11091
111- static char target_buf [1024 ];
112- static char * protocol , * host , * path , * username ;
113- static WCHAR * wusername , * password , * target ;
92+ static WCHAR * wusername , * password , * protocol , * host , * path , target [1024 ];
11493
115- static void write_item (const char * what , WCHAR * wbuf )
94+ static void write_item (const char * what , LPCWSTR wbuf , int wlen )
11695{
11796 char * buf ;
118- int len = WideCharToMultiByte (CP_UTF8 , 0 , wbuf , -1 , NULL , 0 , NULL ,
97+ int len = WideCharToMultiByte (CP_UTF8 , 0 , wbuf , wlen , NULL , 0 , NULL ,
11998 FALSE);
12099 buf = xmalloc (len );
121100
122- if (!WideCharToMultiByte (CP_UTF8 , 0 , wbuf , -1 , buf , len , NULL , FALSE))
101+ if (!WideCharToMultiByte (CP_UTF8 , 0 , wbuf , wlen , buf , len , NULL , FALSE))
123102 die ("WideCharToMultiByte failed!" );
124103
125104 printf ("%s=" , what );
126- fwrite (buf , 1 , len - 1 , stdout );
105+ fwrite (buf , 1 , len , stdout );
127106 putchar ('\n' );
128107 free (buf );
129108}
130109
131- static int match_attr (const CREDENTIALW * cred , const WCHAR * keyword ,
132- const char * want )
110+ /*
111+ * Match an (optional) expected string and a delimiter in the target string,
112+ * consuming the matched text by updating the target pointer.
113+ */
114+ static int match_part (LPCWSTR * ptarget , LPCWSTR want , LPCWSTR delim )
133115{
134- int i ;
135- if (!want )
136- return 1 ;
137-
138- for (i = 0 ; i < cred -> AttributeCount ; ++ i )
139- if (!wcscmp (cred -> Attributes [i ].Keyword , keyword ))
140- return !strcmp ((const char * )cred -> Attributes [i ].Value ,
141- want );
142-
143- return 0 ; /* not found */
116+ LPCWSTR delim_pos , start = * ptarget ;
117+ int len ;
118+
119+ /* find start of delimiter (or end-of-string if delim is empty) */
120+ if (* delim )
121+ delim_pos = wcsstr (start , delim );
122+ else
123+ delim_pos = start + wcslen (start );
124+
125+ /*
126+ * match text up to delimiter, or end of string (e.g. the '/' after
127+ * host is optional if not followed by a path)
128+ */
129+ if (delim_pos )
130+ len = delim_pos - start ;
131+ else
132+ len = wcslen (start );
133+
134+ /* update ptarget if we either found a delimiter or need a match */
135+ if (delim_pos || want )
136+ * ptarget = delim_pos ? delim_pos + wcslen (delim ) : start + len ;
137+
138+ return !want || (!wcsncmp (want , start , len ) && !want [len ]);
144139}
145140
146141static int match_cred (const CREDENTIALW * cred )
147142{
148- return (!wusername || !wcscmp (wusername , cred -> UserName )) &&
149- match_attr (cred , L"git_protocol" , protocol ) &&
150- match_attr (cred , L"git_host" , host ) &&
151- match_attr (cred , L"git_path" , path );
143+ LPCWSTR target = cred -> TargetName ;
144+ if (wusername && wcscmp (wusername , cred -> UserName ))
145+ return 0 ;
146+
147+ return match_part (& target , L"git" , L":" ) &&
148+ match_part (& target , protocol , L"://" ) &&
149+ match_part (& target , wusername , L"@" ) &&
150+ match_part (& target , host , L"/" ) &&
151+ match_part (& target , path , L"" );
152152}
153153
154154static void get_credential (void )
155155{
156- WCHAR * user_buf , * pass_buf ;
157- DWORD user_buf_size = 0 , pass_buf_size = 0 ;
158- CREDENTIALW * * creds , * cred = NULL ;
156+ CREDENTIALW * * creds ;
159157 DWORD num_creds ;
160158 int i ;
161159
@@ -165,90 +163,36 @@ static void get_credential(void)
165163 /* search for the first credential that matches username */
166164 for (i = 0 ; i < num_creds ; ++ i )
167165 if (match_cred (creds [i ])) {
168- cred = creds [i ];
166+ write_item ("username" , creds [i ]-> UserName ,
167+ wcslen (creds [i ]-> UserName ));
168+ write_item ("password" ,
169+ (LPCWSTR )creds [i ]-> CredentialBlob ,
170+ creds [i ]-> CredentialBlobSize / sizeof (WCHAR ));
169171 break ;
170172 }
171- if (!cred )
172- return ;
173-
174- CredUnPackAuthenticationBufferW (0 , cred -> CredentialBlob ,
175- cred -> CredentialBlobSize , NULL , & user_buf_size , NULL , NULL ,
176- NULL , & pass_buf_size );
177-
178- user_buf = xmalloc (user_buf_size * sizeof (WCHAR ));
179- pass_buf = xmalloc (pass_buf_size * sizeof (WCHAR ));
180-
181- if (!CredUnPackAuthenticationBufferW (0 , cred -> CredentialBlob ,
182- cred -> CredentialBlobSize , user_buf , & user_buf_size , NULL , NULL ,
183- pass_buf , & pass_buf_size ))
184- die ("CredUnPackAuthenticationBuffer failed" );
185173
186174 CredFree (creds );
187-
188- /* zero-terminate (sizes include zero-termination) */
189- user_buf [user_buf_size - 1 ] = L'\0' ;
190- pass_buf [pass_buf_size - 1 ] = L'\0' ;
191-
192- write_item ("username" , user_buf );
193- write_item ("password" , pass_buf );
194-
195- free (user_buf );
196- free (pass_buf );
197- }
198-
199- static void write_attr (CREDENTIAL_ATTRIBUTEW * attr , const WCHAR * keyword ,
200- const char * value )
201- {
202- attr -> Keyword = (LPWSTR )keyword ;
203- attr -> Flags = 0 ;
204- attr -> ValueSize = strlen (value ) + 1 ; /* store zero-termination */
205- attr -> Value = (LPBYTE )value ;
206175}
207176
208177static void store_credential (void )
209178{
210179 CREDENTIALW cred ;
211- BYTE * auth_buf ;
212- DWORD auth_buf_size = 0 ;
213- CREDENTIAL_ATTRIBUTEW attrs [CRED_MAX_ATTRIBUTES ];
214180
215181 if (!wusername || !password )
216182 return ;
217183
218- /* query buffer size */
219- CredPackAuthenticationBufferW (0 , wusername , password ,
220- NULL , & auth_buf_size );
221-
222- auth_buf = xmalloc (auth_buf_size );
223-
224- if (!CredPackAuthenticationBufferW (0 , wusername , password ,
225- auth_buf , & auth_buf_size ))
226- die ("CredPackAuthenticationBuffer failed" );
227-
228184 cred .Flags = 0 ;
229185 cred .Type = CRED_TYPE_GENERIC ;
230186 cred .TargetName = target ;
231187 cred .Comment = L"saved by git-credential-wincred" ;
232- cred .CredentialBlobSize = auth_buf_size ;
233- cred .CredentialBlob = auth_buf ;
188+ cred .CredentialBlobSize = ( wcslen ( password )) * sizeof ( WCHAR ) ;
189+ cred .CredentialBlob = ( LPVOID ) password ;
234190 cred .Persist = CRED_PERSIST_LOCAL_MACHINE ;
235- cred .AttributeCount = 1 ;
236- cred .Attributes = attrs ;
191+ cred .AttributeCount = 0 ;
192+ cred .Attributes = NULL ;
237193 cred .TargetAlias = NULL ;
238194 cred .UserName = wusername ;
239195
240- write_attr (attrs , L"git_protocol" , protocol );
241-
242- if (host ) {
243- write_attr (attrs + cred .AttributeCount , L"git_host" , host );
244- cred .AttributeCount ++ ;
245- }
246-
247- if (path ) {
248- write_attr (attrs + cred .AttributeCount , L"git_path" , path );
249- cred .AttributeCount ++ ;
250- }
251-
252196 if (!CredWriteW (& cred , 0 ))
253197 die ("CredWrite failed" );
254198}
@@ -298,13 +242,12 @@ static void read_credential(void)
298242 * v ++ = '\0' ;
299243
300244 if (!strcmp (buf , "protocol" ))
301- protocol = xstrdup (v );
245+ protocol = utf8_to_utf16_dup (v );
302246 else if (!strcmp (buf , "host" ))
303- host = xstrdup (v );
247+ host = utf8_to_utf16_dup (v );
304248 else if (!strcmp (buf , "path" ))
305- path = xstrdup (v );
249+ path = utf8_to_utf16_dup (v );
306250 else if (!strcmp (buf , "username" )) {
307- username = xstrdup (v );
308251 wusername = utf8_to_utf16_dup (v );
309252 } else if (!strcmp (buf , "password" ))
310253 password = utf8_to_utf16_dup (v );
@@ -333,22 +276,20 @@ int main(int argc, char *argv[])
333276 return 0 ;
334277
335278 /* prepare 'target', the unique key for the credential */
336- strncat ( target_buf , "git:" , sizeof ( target_buf ) );
337- strncat ( target_buf , protocol , sizeof ( target_buf ));
338- strncat ( target_buf , "://" , sizeof ( target_buf ));
339- if (username ) {
340- strncat ( target_buf , username , sizeof ( target_buf ));
341- strncat ( target_buf , "@" , sizeof ( target_buf ));
279+ wcscpy ( target , L "git:" );
280+ wcsncat ( target , protocol , ARRAY_SIZE ( target ));
281+ wcsncat ( target , L "://" , ARRAY_SIZE ( target ));
282+ if (wusername ) {
283+ wcsncat ( target , wusername , ARRAY_SIZE ( target ));
284+ wcsncat ( target , L "@" , ARRAY_SIZE ( target ));
342285 }
343286 if (host )
344- strncat ( target_buf , host , sizeof ( target_buf ));
287+ wcsncat ( target , host , ARRAY_SIZE ( target ));
345288 if (path ) {
346- strncat ( target_buf , "/" , sizeof ( target_buf ));
347- strncat ( target_buf , path , sizeof ( target_buf ));
289+ wcsncat ( target , L "/" , ARRAY_SIZE ( target ));
290+ wcsncat ( target , path , ARRAY_SIZE ( target ));
348291 }
349292
350- target = utf8_to_utf16_dup (target_buf );
351-
352293 if (!strcmp (argv [1 ], "get" ))
353294 get_credential ();
354295 else if (!strcmp (argv [1 ], "store" ))
0 commit comments