9
9
10
10
/* common helpers */
11
11
12
+ #define ARRAY_SIZE (x ) (sizeof(x)/sizeof(x[0]))
13
+
12
14
static void die (const char * err , ...)
13
15
{
14
16
char msg [4096 ];
@@ -30,14 +32,6 @@ static void *xmalloc(size_t size)
30
32
return ret ;
31
33
}
32
34
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
-
41
35
/* MinGW doesn't have wincred.h, so we need to define stuff */
42
36
43
37
typedef struct _CREDENTIAL_ATTRIBUTEW {
@@ -67,95 +61,99 @@ typedef struct _CREDENTIALW {
67
61
#define CRED_MAX_ATTRIBUTES 64
68
62
69
63
typedef BOOL (WINAPI * CredWriteWT )(PCREDENTIALW , DWORD );
70
- typedef BOOL (WINAPI * CredUnPackAuthenticationBufferWT )(DWORD , PVOID , DWORD ,
71
- LPWSTR , DWORD * , LPWSTR , DWORD * , LPWSTR , DWORD * );
72
64
typedef BOOL (WINAPI * CredEnumerateWT )(LPCWSTR , DWORD , DWORD * ,
73
65
PCREDENTIALW * * );
74
- typedef BOOL (WINAPI * CredPackAuthenticationBufferWT )(DWORD , LPWSTR , LPWSTR ,
75
- PBYTE , DWORD * );
76
66
typedef VOID (WINAPI * CredFreeT )(PVOID );
77
67
typedef BOOL (WINAPI * CredDeleteWT )(LPCWSTR , DWORD , DWORD );
78
68
79
- static HMODULE advapi , credui ;
69
+ static HMODULE advapi ;
80
70
static CredWriteWT CredWriteW ;
81
- static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW ;
82
71
static CredEnumerateWT CredEnumerateW ;
83
- static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW ;
84
72
static CredFreeT CredFree ;
85
73
static CredDeleteWT CredDeleteW ;
86
74
87
75
static void load_cred_funcs (void )
88
76
{
89
77
/* load DLLs */
90
78
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" );
94
81
95
82
/* get function pointers */
96
83
CredWriteW = (CredWriteWT )GetProcAddress (advapi , "CredWriteW" );
97
- CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT )
98
- GetProcAddress (credui , "CredUnPackAuthenticationBufferW" );
99
84
CredEnumerateW = (CredEnumerateWT )GetProcAddress (advapi ,
100
85
"CredEnumerateW" );
101
- CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT )
102
- GetProcAddress (credui , "CredPackAuthenticationBufferW" );
103
86
CredFree = (CredFreeT )GetProcAddress (advapi , "CredFree" );
104
87
CredDeleteW = (CredDeleteWT )GetProcAddress (advapi , "CredDeleteW" );
105
- if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
106
- !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
107
- !CredDeleteW )
88
+ if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW )
108
89
die ("failed to load functions" );
109
90
}
110
91
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 ];
114
93
115
- static void write_item (const char * what , WCHAR * wbuf )
94
+ static void write_item (const char * what , LPCWSTR wbuf , int wlen )
116
95
{
117
96
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 ,
119
98
FALSE);
120
99
buf = xmalloc (len );
121
100
122
- if (!WideCharToMultiByte (CP_UTF8 , 0 , wbuf , -1 , buf , len , NULL , FALSE))
101
+ if (!WideCharToMultiByte (CP_UTF8 , 0 , wbuf , wlen , buf , len , NULL , FALSE))
123
102
die ("WideCharToMultiByte failed!" );
124
103
125
104
printf ("%s=" , what );
126
- fwrite (buf , 1 , len - 1 , stdout );
105
+ fwrite (buf , 1 , len , stdout );
127
106
putchar ('\n' );
128
107
free (buf );
129
108
}
130
109
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 )
133
115
{
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 ]);
144
139
}
145
140
146
141
static int match_cred (const CREDENTIALW * cred )
147
142
{
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"" );
152
152
}
153
153
154
154
static void get_credential (void )
155
155
{
156
- WCHAR * user_buf , * pass_buf ;
157
- DWORD user_buf_size = 0 , pass_buf_size = 0 ;
158
- CREDENTIALW * * creds , * cred = NULL ;
156
+ CREDENTIALW * * creds ;
159
157
DWORD num_creds ;
160
158
int i ;
161
159
@@ -165,90 +163,36 @@ static void get_credential(void)
165
163
/* search for the first credential that matches username */
166
164
for (i = 0 ; i < num_creds ; ++ i )
167
165
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 ));
169
171
break ;
170
172
}
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" );
185
173
186
174
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 ;
206
175
}
207
176
208
177
static void store_credential (void )
209
178
{
210
179
CREDENTIALW cred ;
211
- BYTE * auth_buf ;
212
- DWORD auth_buf_size = 0 ;
213
- CREDENTIAL_ATTRIBUTEW attrs [CRED_MAX_ATTRIBUTES ];
214
180
215
181
if (!wusername || !password )
216
182
return ;
217
183
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
-
228
184
cred .Flags = 0 ;
229
185
cred .Type = CRED_TYPE_GENERIC ;
230
186
cred .TargetName = target ;
231
187
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 ;
234
190
cred .Persist = CRED_PERSIST_LOCAL_MACHINE ;
235
- cred .AttributeCount = 1 ;
236
- cred .Attributes = attrs ;
191
+ cred .AttributeCount = 0 ;
192
+ cred .Attributes = NULL ;
237
193
cred .TargetAlias = NULL ;
238
194
cred .UserName = wusername ;
239
195
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
-
252
196
if (!CredWriteW (& cred , 0 ))
253
197
die ("CredWrite failed" );
254
198
}
@@ -298,13 +242,12 @@ static void read_credential(void)
298
242
* v ++ = '\0' ;
299
243
300
244
if (!strcmp (buf , "protocol" ))
301
- protocol = xstrdup (v );
245
+ protocol = utf8_to_utf16_dup (v );
302
246
else if (!strcmp (buf , "host" ))
303
- host = xstrdup (v );
247
+ host = utf8_to_utf16_dup (v );
304
248
else if (!strcmp (buf , "path" ))
305
- path = xstrdup (v );
249
+ path = utf8_to_utf16_dup (v );
306
250
else if (!strcmp (buf , "username" )) {
307
- username = xstrdup (v );
308
251
wusername = utf8_to_utf16_dup (v );
309
252
} else if (!strcmp (buf , "password" ))
310
253
password = utf8_to_utf16_dup (v );
@@ -333,22 +276,20 @@ int main(int argc, char *argv[])
333
276
return 0 ;
334
277
335
278
/* 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 ));
342
285
}
343
286
if (host )
344
- strncat ( target_buf , host , sizeof ( target_buf ));
287
+ wcsncat ( target , host , ARRAY_SIZE ( target ));
345
288
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 ));
348
291
}
349
292
350
- target = utf8_to_utf16_dup (target_buf );
351
-
352
293
if (!strcmp (argv [1 ], "get" ))
353
294
get_credential ();
354
295
else if (!strcmp (argv [1 ], "store" ))
0 commit comments