1 /*
2  * Credential Function Tests
3  *
4  * Copyright 2007 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wincred.h"
27 
28 #include "wine/test.h"
29 
30 static BOOL (WINAPI *pCredDeleteA)(LPCSTR,DWORD,DWORD);
31 static BOOL (WINAPI *pCredEnumerateA)(LPCSTR,DWORD,DWORD *,PCREDENTIALA **);
32 static VOID (WINAPI *pCredFree)(PVOID);
33 static BOOL (WINAPI *pCredGetSessionTypes)(DWORD,LPDWORD);
34 static BOOL (WINAPI *pCredReadA)(LPCSTR,DWORD,DWORD,PCREDENTIALA *);
35 static BOOL (WINAPI *pCredRenameA)(LPCSTR,LPCSTR,DWORD,DWORD);
36 static BOOL (WINAPI *pCredWriteA)(PCREDENTIALA,DWORD);
37 static BOOL (WINAPI *pCredReadDomainCredentialsA)(PCREDENTIAL_TARGET_INFORMATIONA,DWORD,DWORD*,PCREDENTIALA**);
38 static BOOL (WINAPI *pCredMarshalCredentialA)(CRED_MARSHAL_TYPE,PVOID,LPSTR *);
39 static BOOL (WINAPI *pCredUnmarshalCredentialA)(LPCSTR,PCRED_MARSHAL_TYPE,PVOID);
40 static BOOL (WINAPI *pCredIsMarshaledCredentialA)(LPCSTR);
41 
42 #define TEST_TARGET_NAME  "credtest.winehq.org"
43 #define TEST_TARGET_NAME2 "credtest2.winehq.org"
44 static const WCHAR TEST_PASSWORD[] = {'p','4','$','$','w','0','r','d','!',0};
45 
46 static void test_CredReadA(void)
47 {
48     BOOL ret;
49     PCREDENTIALA cred;
50 
51     SetLastError(0xdeadbeef);
52     ret = pCredReadA(TEST_TARGET_NAME, -1, 0, &cred);
53     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
54         "CredReadA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
55         GetLastError());
56 
57     SetLastError(0xdeadbeef);
58     ret = pCredReadA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0xdeadbeef, &cred);
59     ok(!ret && ( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER ),
60         "CredReadA should have failed with ERROR_INVALID_FLAGS or ERROR_INVALID_PARAMETER instead of %d\n",
61         GetLastError());
62 
63     SetLastError(0xdeadbeef);
64     ret = pCredReadA(NULL, CRED_TYPE_GENERIC, 0, &cred);
65     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
66         "CredReadA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
67         GetLastError());
68 }
69 
70 static void test_CredWriteA(void)
71 {
72     CREDENTIALA new_cred;
73     BOOL ret;
74 
75     SetLastError(0xdeadbeef);
76     ret = pCredWriteA(NULL, 0);
77     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
78         "CredWriteA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
79         GetLastError());
80 
81     new_cred.Flags = 0;
82     new_cred.Type = CRED_TYPE_GENERIC;
83     new_cred.TargetName = NULL;
84     new_cred.Comment = (char *)"Comment";
85     new_cred.CredentialBlobSize = 0;
86     new_cred.CredentialBlob = NULL;
87     new_cred.Persist = CRED_PERSIST_ENTERPRISE;
88     new_cred.AttributeCount = 0;
89     new_cred.Attributes = NULL;
90     new_cred.TargetAlias = NULL;
91     new_cred.UserName = (char *)"winetest";
92 
93     SetLastError(0xdeadbeef);
94     ret = pCredWriteA(&new_cred, 0);
95     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
96         "CredWriteA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
97         GetLastError());
98 
99     new_cred.TargetName = (char *)TEST_TARGET_NAME;
100     new_cred.Type = CRED_TYPE_DOMAIN_PASSWORD;
101 
102     SetLastError(0xdeadbeef);
103     ret = pCredWriteA(&new_cred, 0);
104     if (ret)
105     {
106         ok(GetLastError() == ERROR_SUCCESS ||
107            GetLastError() == ERROR_IO_PENDING, /* Vista */
108            "Expected ERROR_IO_PENDING, got %d\n", GetLastError());
109     }
110     else
111     {
112         ok(GetLastError() == ERROR_BAD_USERNAME ||
113            GetLastError() == ERROR_NO_SUCH_LOGON_SESSION, /* Vista */
114            "CredWrite with username without domain should return ERROR_BAD_USERNAME"
115            "or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError());
116     }
117 
118     new_cred.UserName = NULL;
119     SetLastError(0xdeadbeef);
120     ret = pCredWriteA(&new_cred, 0);
121     ok(!ret && GetLastError() == ERROR_BAD_USERNAME,
122         "CredWriteA with NULL username should have failed with ERROR_BAD_USERNAME instead of %d\n",
123         GetLastError());
124 
125     new_cred.UserName = (char *)"winetest";
126     new_cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
127     SetLastError(0xdeadbeef);
128     ret = pCredWriteA(&new_cred, 0);
129     ok(ret || broken(!ret), "CredWriteA failed with error %u\n", GetLastError());
130     if (ret)
131     {
132         ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_DOMAIN_PASSWORD, 0);
133         ok(ret, "CredDeleteA failed with error %u\n", GetLastError());
134     }
135     new_cred.Type = CRED_TYPE_GENERIC;
136     SetLastError(0xdeadbeef);
137     ret = pCredWriteA(&new_cred, 0);
138     ok(ret || broken(!ret), "CredWriteA failed with error %u\n", GetLastError());
139     if  (ret)
140     {
141         ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0);
142         ok(ret, "CredDeleteA failed with error %u\n", GetLastError());
143     }
144     new_cred.Persist = CRED_PERSIST_SESSION;
145     ret = pCredWriteA(&new_cred, 0);
146     ok(ret, "CredWriteA failed with error %u\n", GetLastError());
147 
148     ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0);
149     ok(ret, "CredDeleteA failed with error %u\n", GetLastError());
150 
151     new_cred.Type = CRED_TYPE_DOMAIN_PASSWORD;
152     SetLastError(0xdeadbeef);
153     ret = pCredWriteA(&new_cred, 0);
154     ok(ret || broken(!ret), "CredWriteA failed with error %u\n", GetLastError());
155     if (ret)
156     {
157         ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_DOMAIN_PASSWORD, 0);
158         ok(ret, "CredDeleteA failed with error %u\n", GetLastError());
159     }
160     new_cred.UserName = NULL;
161     SetLastError(0xdeadbeef);
162     ret = pCredWriteA(&new_cred, 0);
163     ok(!ret, "CredWriteA succeeded\n");
164     ok(GetLastError() == ERROR_BAD_USERNAME, "got %u\n", GetLastError());
165 }
166 
167 static void test_CredDeleteA(void)
168 {
169     BOOL ret;
170 
171     SetLastError(0xdeadbeef);
172     ret = pCredDeleteA(TEST_TARGET_NAME, -1, 0);
173     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
174         "CredDeleteA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
175         GetLastError());
176 
177     SetLastError(0xdeadbeef);
178     ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0xdeadbeef);
179     ok(!ret && ( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER /* Vista */ ),
180         "CredDeleteA should have failed with ERROR_INVALID_FLAGS or ERROR_INVALID_PARAMETER instead of %d\n",
181         GetLastError());
182 }
183 
184 static void test_CredReadDomainCredentialsA(void)
185 {
186     BOOL ret;
187     char target_name[] = "no_such_target";
188     CREDENTIAL_TARGET_INFORMATIONA info = {target_name, NULL, target_name, NULL, NULL, NULL, NULL, 0, 0, NULL};
189     DWORD count;
190     PCREDENTIALA* creds;
191 
192     if (!pCredReadDomainCredentialsA)
193     {
194         win_skip("CredReadDomainCredentialsA() is not implemented\n");
195         return;
196     }
197 
198     /* these two tests would crash on both native and Wine. Implementations
199      * does not check for NULL output pointers and try to zero them out early */
200 if(0)
201 {
202     ret = pCredReadDomainCredentialsA(&info, 0, NULL, &creds);
203     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "!\n");
204     ret = pCredReadDomainCredentialsA(&info, 0, &count, NULL);
205     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "!\n");
206 }
207 
208     SetLastError(0xdeadbeef);
209     ret = pCredReadDomainCredentialsA(NULL, 0, &count, &creds);
210     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
211         "CredReadDomainCredentialsA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
212         GetLastError());
213 
214     SetLastError(0xdeadbeef);
215     creds = (void*)0x12345;
216     count = 2;
217     ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds);
218     ok(!ret && GetLastError() == ERROR_NOT_FOUND,
219         "CredReadDomainCredentialsA should have failed with ERROR_NOT_FOUND instead of %d\n",
220         GetLastError());
221     ok(count ==0 && creds == NULL, "CredReadDomainCredentialsA must not return any result\n");
222 
223     info.TargetName = NULL;
224 
225     SetLastError(0xdeadbeef);
226     ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds);
227     ok(!ret, "CredReadDomainCredentialsA should have failed\n");
228     ok(GetLastError() == ERROR_NOT_FOUND ||
229         GetLastError() == ERROR_INVALID_PARAMETER, /* Vista, W2K8 */
230         "Expected ERROR_NOT_FOUND or ERROR_INVALID_PARAMETER instead of %d\n",
231         GetLastError());
232 
233     info.DnsServerName = NULL;
234 
235     SetLastError(0xdeadbeef);
236     ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds);
237     ok(!ret, "CredReadDomainCredentialsA should have failed\n");
238     ok(GetLastError() == ERROR_NOT_FOUND ||
239         GetLastError() == ERROR_INVALID_PARAMETER, /* Vista, W2K8 */
240         "Expected ERROR_NOT_FOUND or ERROR_INVALID_PARAMETER instead of %d\n",
241         GetLastError());
242 }
243 
244 static void check_blob(int line, DWORD cred_type, PCREDENTIALA cred)
245 {
246     if (cred_type == CRED_TYPE_DOMAIN_PASSWORD)
247     {
248         todo_ros
249         ok_(__FILE__, line)(cred->CredentialBlobSize == 0, "expected CredentialBlobSize of 0 but got %d\n", cred->CredentialBlobSize);
250         todo_ros
251         ok_(__FILE__, line)(!cred->CredentialBlob, "expected NULL credentials but got %p\n", cred->CredentialBlob);
252     }
253     else
254     {
255         DWORD size=sizeof(TEST_PASSWORD);
256         ok_(__FILE__, line)(cred->CredentialBlobSize == size, "expected CredentialBlobSize of %u but got %u\n", size, cred->CredentialBlobSize);
257         ok_(__FILE__, line)(cred->CredentialBlob != NULL, "CredentialBlob should be present\n");
258         if (cred->CredentialBlob)
259             ok_(__FILE__, line)(!memcmp(cred->CredentialBlob, TEST_PASSWORD, size), "wrong CredentialBlob\n");
260     }
261 }
262 
263 static void test_generic(void)
264 {
265     BOOL ret;
266     DWORD count, i;
267     PCREDENTIALA *creds;
268     CREDENTIALA new_cred;
269     PCREDENTIALA cred;
270     BOOL found = FALSE;
271 
272     new_cred.Flags = 0;
273     new_cred.Type = CRED_TYPE_GENERIC;
274     new_cred.TargetName = (char *)TEST_TARGET_NAME;
275     new_cred.Comment = (char *)"Comment";
276     new_cred.CredentialBlobSize = sizeof(TEST_PASSWORD);
277     new_cred.CredentialBlob = (LPBYTE)TEST_PASSWORD;
278     new_cred.Persist = CRED_PERSIST_ENTERPRISE;
279     new_cred.AttributeCount = 0;
280     new_cred.Attributes = NULL;
281     new_cred.TargetAlias = NULL;
282     new_cred.UserName = (char *)"winetest";
283 
284     ret = pCredWriteA(&new_cred, 0);
285     ok(ret || broken(GetLastError() == ERROR_NO_SUCH_LOGON_SESSION),
286        "CredWriteA failed with error %d\n", GetLastError());
287     if (!ret)
288     {
289         skip("couldn't write generic credentials, skipping tests\n");
290         return;
291     }
292 
293     ret = pCredEnumerateA(NULL, 0, &count, &creds);
294     ok(ret, "CredEnumerateA failed with error %d\n", GetLastError());
295 
296     for (i = 0; i < count; i++)
297     {
298         if (creds[i]->TargetName && !strcmp(creds[i]->TargetName, TEST_TARGET_NAME))
299         {
300             ok(creds[i]->Type == CRED_TYPE_GENERIC ||
301                creds[i]->Type == CRED_TYPE_DOMAIN_PASSWORD, /* Vista */
302                "expected creds[%d]->Type CRED_TYPE_GENERIC or CRED_TYPE_DOMAIN_PASSWORD but got %d\n", i, creds[i]->Type);
303             ok(!creds[i]->Flags, "expected creds[%d]->Flags 0 but got 0x%x\n", i, creds[i]->Flags);
304             ok(!strcmp(creds[i]->Comment, "Comment"), "expected creds[%d]->Comment \"Comment\" but got \"%s\"\n", i, creds[i]->Comment);
305             check_blob(__LINE__, creds[i]->Type, creds[i]);
306             ok(creds[i]->Persist, "expected creds[%d]->Persist CRED_PERSIST_ENTERPRISE but got %d\n", i, creds[i]->Persist);
307             ok(!strcmp(creds[i]->UserName, "winetest"), "expected creds[%d]->UserName \"winetest\" but got \"%s\"\n", i, creds[i]->UserName);
308             found = TRUE;
309         }
310     }
311     pCredFree(creds);
312     ok(found, "credentials not found\n");
313 
314     ret = pCredReadA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0, &cred);
315     ok(ret, "CredReadA failed with error %d\n", GetLastError());
316     pCredFree(cred);
317 
318     ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0);
319     ok(ret, "CredDeleteA failed with error %d\n", GetLastError());
320 }
321 
322 static void test_domain_password(DWORD cred_type)
323 {
324     BOOL ret;
325     DWORD count, i;
326     PCREDENTIALA *creds;
327     CREDENTIALA new_cred;
328     PCREDENTIALA cred;
329     BOOL found = FALSE;
330 
331     new_cred.Flags = 0;
332     new_cred.Type = cred_type;
333     new_cred.TargetName = (char *)TEST_TARGET_NAME;
334     new_cred.Comment = (char *)"Comment";
335     new_cred.CredentialBlobSize = sizeof(TEST_PASSWORD);
336     new_cred.CredentialBlob = (LPBYTE)TEST_PASSWORD;
337     new_cred.Persist = CRED_PERSIST_ENTERPRISE;
338     new_cred.AttributeCount = 0;
339     new_cred.Attributes = NULL;
340     new_cred.TargetAlias = NULL;
341     new_cred.UserName = (char *)"test\\winetest";
342     ret = pCredWriteA(&new_cred, 0);
343     if (!ret && GetLastError() == ERROR_NO_SUCH_LOGON_SESSION)
344     {
345         skip("CRED_TYPE_DOMAIN_PASSWORD credentials are not supported "
346              "or are disabled. Skipping\n");
347         return;
348     }
349     ok(ret, "CredWriteA failed with error %d\n", GetLastError());
350 
351     ret = pCredEnumerateA(NULL, 0, &count, &creds);
352     ok(ret, "CredEnumerateA failed with error %d\n", GetLastError());
353 
354     for (i = 0; i < count; i++)
355     {
356         if (creds[i]->TargetName && !strcmp(creds[i]->TargetName, TEST_TARGET_NAME))
357         {
358             ok(creds[i]->Type == cred_type, "expected creds[%d]->Type CRED_TYPE_DOMAIN_PASSWORD but got %d\n", i, creds[i]->Type);
359             ok(!creds[i]->Flags, "expected creds[%d]->Flags 0 but got 0x%x\n", i, creds[i]->Flags);
360             ok(!strcmp(creds[i]->Comment, "Comment"), "expected creds[%d]->Comment \"Comment\" but got \"%s\"\n", i, creds[i]->Comment);
361             check_blob(__LINE__, cred_type, creds[i]);
362             ok(creds[i]->Persist, "expected creds[%d]->Persist CRED_PERSIST_ENTERPRISE but got %d\n", i, creds[i]->Persist);
363             ok(!strcmp(creds[i]->UserName, "test\\winetest"), "expected creds[%d]->UserName \"winetest\" but got \"%s\"\n", i, creds[i]->UserName);
364             found = TRUE;
365         }
366     }
367     pCredFree(creds);
368     ok(found, "credentials not found\n");
369 
370     ret = pCredReadA(TEST_TARGET_NAME, cred_type, 0, &cred);
371     ok(ret, "CredReadA failed with error %d\n", GetLastError());
372     if (ret)  /* don't check the values of cred, if CredReadA failed. */
373     {
374         check_blob(__LINE__, cred_type, cred);
375         pCredFree(cred);
376     }
377 
378     ret = pCredDeleteA(TEST_TARGET_NAME, cred_type, 0);
379     ok(ret, "CredDeleteA failed with error %d\n", GetLastError());
380 }
381 
382 static void test_CredMarshalCredentialA(void)
383 {
384     static WCHAR emptyW[] = {0};
385     static WCHAR tW[] = {'t',0};
386     static WCHAR teW[] = {'t','e',0};
387     static WCHAR tesW[] = {'t','e','s',0};
388     static WCHAR testW[] = {'t','e','s','t',0};
389     static WCHAR test1W[] = {'t','e','s','t','1',0};
390     CERT_CREDENTIAL_INFO cert;
391     USERNAME_TARGET_CREDENTIAL_INFO username;
392     DWORD error;
393     char *str;
394     BOOL ret;
395 
396     SetLastError( 0xdeadbeef );
397     ret = pCredMarshalCredentialA( 0, NULL, NULL );
398     error = GetLastError();
399     ok( !ret, "unexpected success\n" );
400     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
401 
402     memset( cert.rgbHashOfCert, 0, sizeof(cert.rgbHashOfCert) );
403     cert.cbSize = sizeof(cert);
404     SetLastError( 0xdeadbeef );
405     ret = pCredMarshalCredentialA( 0, &cert, NULL );
406     error = GetLastError();
407     ok( !ret, "unexpected success\n" );
408     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
409 
410     str = (char *)0xdeadbeef;
411     SetLastError( 0xdeadbeef );
412     ret = pCredMarshalCredentialA( 0, &cert, &str );
413     error = GetLastError();
414     ok( !ret, "unexpected success\n" );
415     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
416     ok( str == (char *)0xdeadbeef, "got %p\n", str );
417 
418     SetLastError( 0xdeadbeef );
419     ret = pCredMarshalCredentialA( CertCredential, NULL, NULL );
420     error = GetLastError();
421     ok( !ret, "unexpected success\n" );
422     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
423 
424     if (0) { /* crash */
425     SetLastError( 0xdeadbeef );
426     ret = pCredMarshalCredentialA( CertCredential, &cert, NULL );
427     error = GetLastError();
428     ok( !ret, "unexpected success\n" );
429     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
430     }
431 
432     cert.cbSize = 0;
433     str = (char *)0xdeadbeef;
434     SetLastError( 0xdeadbeef );
435     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
436     error = GetLastError();
437     ok( !ret, "unexpected success\n" );
438     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
439     ok( str == (char *)0xdeadbeef, "got %p\n", str );
440 
441     cert.cbSize = sizeof(cert) + 4;
442     str = NULL;
443     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
444     ok( ret, "unexpected failure %u\n", GetLastError() );
445     ok( str != NULL, "str not set\n" );
446     ok( !lstrcmpA( str, "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str );
447     pCredFree( str );
448 
449     cert.cbSize = sizeof(cert);
450     cert.rgbHashOfCert[0] = 2;
451     str = NULL;
452     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
453     ok( ret, "unexpected failure %u\n", GetLastError() );
454     ok( str != NULL, "str not set\n" );
455     ok( !lstrcmpA( str, "@@BCAAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str );
456     pCredFree( str );
457 
458     cert.rgbHashOfCert[0] = 255;
459     str = NULL;
460     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
461     ok( ret, "unexpected failure %u\n", GetLastError() );
462     ok( str != NULL, "str not set\n" );
463     ok( !lstrcmpA( str, "@@B-DAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str );
464     pCredFree( str );
465 
466     cert.rgbHashOfCert[0] = 1;
467     cert.rgbHashOfCert[1] = 1;
468     str = NULL;
469     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
470     ok( ret, "unexpected failure %u\n", GetLastError() );
471     ok( str != NULL, "str not set\n" );
472     ok( !lstrcmpA( str, "@@BBEAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str );
473     pCredFree( str );
474 
475     cert.rgbHashOfCert[0] = 1;
476     cert.rgbHashOfCert[1] = 1;
477     cert.rgbHashOfCert[2] = 1;
478     str = NULL;
479     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
480     ok( ret, "unexpected failure %u\n", GetLastError() );
481     ok( str != NULL, "str not set\n" );
482     ok( !lstrcmpA( str, "@@BBEQAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str );
483     pCredFree( str );
484 
485     memset( cert.rgbHashOfCert, 0, sizeof(cert.rgbHashOfCert) );
486     cert.rgbHashOfCert[0] = 'W';
487     cert.rgbHashOfCert[1] = 'i';
488     cert.rgbHashOfCert[2] = 'n';
489     cert.rgbHashOfCert[3] = 'e';
490     str = NULL;
491     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
492     ok( ret, "unexpected failure %u\n", GetLastError() );
493     ok( str != NULL, "str not set\n" );
494     ok( !lstrcmpA( str, "@@BXlmblBAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str );
495     pCredFree( str );
496 
497     memset( cert.rgbHashOfCert, 0xff, sizeof(cert.rgbHashOfCert) );
498     str = NULL;
499     ret = pCredMarshalCredentialA( CertCredential, &cert, &str );
500     ok( ret, "unexpected failure %u\n", GetLastError() );
501     ok( str != NULL, "str not set\n" );
502     ok( !lstrcmpA( str, "@@B--------------------------P" ), "got %s\n", str );
503     pCredFree( str );
504 
505     username.UserName = NULL;
506     str = (char *)0xdeadbeef;
507     SetLastError( 0xdeadbeef );
508     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
509     error = GetLastError();
510     ok( !ret, "unexpected success\n" );
511     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
512     ok( str == (char *)0xdeadbeef, "got %p\n", str );
513 
514     username.UserName = emptyW;
515     str = (char *)0xdeadbeef;
516     SetLastError( 0xdeadbeef );
517     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
518     error = GetLastError();
519     ok( !ret, "unexpected success\n" );
520     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
521     ok( str == (char *)0xdeadbeef, "got %p\n", str );
522 
523     username.UserName = tW;
524     str = NULL;
525     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
526     ok( ret, "unexpected failure %u\n", GetLastError() );
527     ok( str != NULL, "str not set\n" );
528     ok( !lstrcmpA( str, "@@CCAAAAA0BA" ), "got %s\n", str );
529     pCredFree( str );
530 
531     username.UserName = teW;
532     str = NULL;
533     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
534     ok( ret, "unexpected failure %u\n", GetLastError() );
535     ok( str != NULL, "str not set\n" );
536     ok( !lstrcmpA( str, "@@CEAAAAA0BQZAA" ), "got %s\n", str );
537     pCredFree( str );
538 
539     username.UserName = tesW;
540     str = NULL;
541     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
542     ok( ret, "unexpected failure %u\n", GetLastError() );
543     ok( str != NULL, "str not set\n" );
544     ok( !lstrcmpA( str, "@@CGAAAAA0BQZAMHA" ), "got %s\n", str );
545     pCredFree( str );
546 
547     username.UserName = testW;
548     str = NULL;
549     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
550     ok( ret, "unexpected failure %u\n", GetLastError() );
551     ok( str != NULL, "str not set\n" );
552     ok( !lstrcmpA( str, "@@CIAAAAA0BQZAMHA0BA" ), "got %s\n", str );
553     pCredFree( str );
554 
555     username.UserName = test1W;
556     str = NULL;
557     ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str );
558     ok( ret, "unexpected failure %u\n", GetLastError() );
559     ok( str != NULL, "str not set\n" );
560     ok( !lstrcmpA( str, "@@CKAAAAA0BQZAMHA0BQMAA" ), "got %s\n", str );
561     pCredFree( str );
562 }
563 
564 static void test_CredUnmarshalCredentialA(void)
565 {
566     static const UCHAR cert_empty[CERT_HASH_LENGTH] = {0};
567     static const UCHAR cert_wine[CERT_HASH_LENGTH] = {'W','i','n','e',0};
568     static const WCHAR tW[] = {'t',0};
569     static const WCHAR teW[] = {'t','e',0};
570     static const WCHAR tesW[] = {'t','e','s',0};
571     static const WCHAR testW[] = {'t','e','s','t',0};
572     void *p;
573     CERT_CREDENTIAL_INFO *cert;
574     const UCHAR *hash;
575     USERNAME_TARGET_CREDENTIAL_INFO *username;
576     CRED_MARSHAL_TYPE type;
577     unsigned int i, j;
578     DWORD error;
579     BOOL ret;
580     const struct {
581         const char *cred;
582         CRED_MARSHAL_TYPE type;
583         const void *unmarshaled;
584     } tests[] = {
585         { "", 0, NULL },
586         { "@", 0, NULL },
587         { "@@", 0, NULL },
588         { "@@@", 0, NULL },
589         { "@@A", 0, NULL },
590         { "@@E", 4, NULL },
591         { "@@Z", 25, NULL },
592         { "@@a", 26, NULL },
593         { "@@0", 52, NULL },
594         { "@@#", 62, NULL },
595         { "@@-", 63, NULL },
596         { "@@B", CertCredential, NULL },
597         { "@@BA", CertCredential, NULL },
598         { "@@BAAAAAAAAAAAAAAAAAAAAAAAAAA", CertCredential, NULL },
599         { "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAAA", CertCredential, NULL },
600         { "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA", CertCredential, cert_empty },
601         { "@@BXlmblBAAAAAAAAAAAAAAAAAAAAA", CertCredential, cert_wine },
602         { "@@C", UsernameTargetCredential, NULL },
603         { "@@CA", UsernameTargetCredential, NULL },
604         { "@@CAAAAAA", UsernameTargetCredential, NULL },
605         { "@@CAAAAAA0B", UsernameTargetCredential, NULL },
606         { "@@CAAAAAA0BA", UsernameTargetCredential, NULL },
607         { "@@CCAAAAA0BA", UsernameTargetCredential, tW },
608         { "@@CEAAAAA0BA", UsernameTargetCredential, NULL },
609         { "@@CEAAAAA0BAd", UsernameTargetCredential, NULL },
610         { "@@CEAAAAA0BAdA", UsernameTargetCredential, NULL },
611         { "@@CEAAAAA0BQZAA", UsernameTargetCredential, teW },
612         { "@@CEAAAAA0BQZAQ", UsernameTargetCredential, teW },
613         { "@@CEAAAAA0BQZAg", UsernameTargetCredential, teW },
614         { "@@CEAAAAA0BQZAw", UsernameTargetCredential, teW },
615         { "@@CEAAAAA0BQZAAA", UsernameTargetCredential, NULL },
616         { "@@CGAAAAA0BQZAMH", UsernameTargetCredential, NULL },
617         { "@@CGAAAAA0BQZAMHA", UsernameTargetCredential, tesW },
618         { "@@CGAAAAA0BQZAMHAA", UsernameTargetCredential, NULL },
619         { "@@CCAAAAA0BAA", UsernameTargetCredential, NULL },
620         { "@@CBAAAAA0BAA", UsernameTargetCredential, NULL },
621         { "@@CAgAAAA0BAA", UsernameTargetCredential, NULL },
622         { "@@CIAAAAA0BQZAMHA0BA", UsernameTargetCredential, testW },
623         { "@@CA-----0BQZAMHA0BA", UsernameTargetCredential, NULL },
624     };
625 
626     SetLastError( 0xdeadbeef );
627     ret = pCredUnmarshalCredentialA( NULL, NULL, NULL );
628     error = GetLastError();
629     ok( !ret, "unexpected success\n" );
630     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
631 
632     cert = NULL;
633     SetLastError( 0xdeadbeef );
634     ret = pCredUnmarshalCredentialA( NULL, NULL, (void **)&cert );
635     error = GetLastError();
636     ok( !ret, "unexpected success\n" );
637     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
638 
639     type = 0;
640     cert = NULL;
641     SetLastError( 0xdeadbeef );
642     ret = pCredUnmarshalCredentialA( NULL, &type, (void **)&cert );
643     error = GetLastError();
644     ok( !ret, "unexpected success\n" );
645     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
646 
647     if (0) { /* crash */
648     SetLastError( 0xdeadbeef );
649     ret = pCredUnmarshalCredentialA( "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA", &type, NULL );
650     error = GetLastError();
651     ok( !ret, "unexpected success\n" );
652     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
653 
654     SetLastError( 0xdeadbeef );
655     ret = pCredUnmarshalCredentialA( "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA", NULL, (void **)&cert );
656     error = GetLastError();
657     ok( !ret, "unexpected success\n" );
658     ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error );
659     }
660 
661     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
662     {
663         SetLastError(0xdeadbeef);
664         type = 0;
665         p = NULL;
666         ret = pCredUnmarshalCredentialA(tests[i].cred, &type, &p);
667         error = GetLastError();
668         if (tests[i].unmarshaled)
669         {
670             ok(ret, "[%u] unexpected failure %u\n", i, error);
671             ok(type == tests[i].type, "[%u] got %u\n", i, type);
672             ok(p != NULL, "[%u] returned pointer is NULL\n", i);
673             if (tests[i].type == CertCredential)
674             {
675                 cert = p;
676                 hash = tests[i].unmarshaled;
677                 ok(cert->cbSize == sizeof(*cert),
678                    "[%u] wrong size %u\n", i, cert->cbSize);
679                 for (j = 0; j < sizeof(cert->rgbHashOfCert); j++)
680                     ok(cert->rgbHashOfCert[j] == hash[j], "[%u] wrong data\n", i);
681             }
682             else if (tests[i].type == UsernameTargetCredential)
683             {
684                 username = p;
685                 ok(username->UserName != NULL, "[%u] UserName is NULL\n", i);
686                 ok(!lstrcmpW(username->UserName, tests[i].unmarshaled),
687                    "[%u] got %s\n", i, wine_dbgstr_w(username->UserName));
688             }
689         }
690         else
691         {
692             ok(!ret, "[%u] unexpected success\n", i);
693             ok(error == ERROR_INVALID_PARAMETER, "[%u] got %u\n", i, error);
694             ok(type == tests[i].type, "[%u] got %u\n", i, type);
695             ok(p == NULL, "[%u] returned pointer is not NULL\n", i);
696         }
697 
698         if (ret)
699             pCredFree(p);
700     }
701 }
702 
703 static void test_CredIsMarshaledCredentialA(void)
704 {
705     int i;
706     BOOL res;
707     BOOL expected = TRUE;
708 
709     const char * ptr[] = {
710         /* CertCredential */
711         "@@BXlmblBAAAAAAAAAAAAAAAAAAAAA",   /* hash for 'W','i','n','e' */
712         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA",   /* hash for all 0 */
713 
714         /* UsernameTargetCredential */
715         "@@CCAAAAA0BA",                     /* "t" */
716         "@@CIAAAAA0BQZAMHA0BA",             /* "test" */
717 
718         /* todo: BinaryBlobCredential */
719 
720         /* not marshaled names return always FALSE */
721         "winetest",
722         "",
723         "@@",
724         "@@A",
725         "@@AA",
726         "@@AAA",
727         "@@B",
728         "@@BB",
729         "@@BBB",
730 
731         /* CertCredential */
732         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAAA",  /* to long */
733         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAA",    /* to short */
734         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAA+",   /* bad char */
735         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAA:",
736         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAA>",
737         "@@BAAAAAAAAAAAAAAAAAAAAAAAAAA<",
738 
739         "@@C",
740         "@@CC",
741         "@@CCC",
742         "@@D",
743         "@@DD",
744         "@@DDD",
745         NULL};
746 
747     for (i = 0; ptr[i]; i++)
748     {
749         if (*ptr[i] != '@')
750             expected = FALSE;
751 
752         SetLastError(0xdeadbeef);
753         res = pCredIsMarshaledCredentialA(ptr[i]);
754         if (expected)
755             ok(res != FALSE, "%d: got %d and %u for %s (expected TRUE)\n", i, res, GetLastError(), ptr[i]);
756         else
757         {
758             /* Windows returns ERROR_INVALID_PARAMETER here, but that's not documented */
759             ok(!res, "%d: got %d and %u for %s (expected FALSE)\n", i, res, GetLastError(), ptr[i]);
760         }
761     }
762 }
763 
764 START_TEST(cred)
765 {
766     DWORD persists[CRED_TYPE_MAXIMUM];
767     HMODULE mod = GetModuleHandleA("advapi32.dll");
768 
769     pCredEnumerateA = (void *)GetProcAddress(mod, "CredEnumerateA");
770     pCredFree = (void *)GetProcAddress(mod, "CredFree");
771     pCredGetSessionTypes = (void *)GetProcAddress(mod, "CredGetSessionTypes");
772     pCredWriteA = (void *)GetProcAddress(mod, "CredWriteA");
773     pCredDeleteA = (void *)GetProcAddress(mod, "CredDeleteA");
774     pCredReadA = (void *)GetProcAddress(mod, "CredReadA");
775     pCredRenameA = (void *)GetProcAddress(mod, "CredRenameA");
776     pCredReadDomainCredentialsA = (void *)GetProcAddress(mod, "CredReadDomainCredentialsA");
777     pCredMarshalCredentialA = (void *)GetProcAddress(mod, "CredMarshalCredentialA");
778     pCredUnmarshalCredentialA = (void *)GetProcAddress(mod, "CredUnmarshalCredentialA");
779     pCredIsMarshaledCredentialA = (void *)GetProcAddress(mod, "CredIsMarshaledCredentialA");
780 
781     if (!pCredEnumerateA || !pCredFree || !pCredWriteA || !pCredDeleteA || !pCredReadA)
782     {
783         win_skip("credentials functions not present in advapi32.dll\n");
784         return;
785     }
786 
787     if (pCredGetSessionTypes)
788     {
789         BOOL ret;
790         DWORD i;
791         ret = pCredGetSessionTypes(CRED_TYPE_MAXIMUM, persists);
792         ok(ret, "CredGetSessionTypes failed with error %d\n", GetLastError());
793         ok(persists[0] == CRED_PERSIST_NONE, "persists[0] = %u instead of CRED_PERSIST_NONE\n", persists[0]);
794         for (i=0; i < CRED_TYPE_MAXIMUM; i++)
795             ok(persists[i] <= CRED_PERSIST_ENTERPRISE, "bad value for persists[%u]: %u\n", i, persists[i]);
796     }
797     else
798         memset(persists, CRED_PERSIST_ENTERPRISE, sizeof(persists));
799 
800     test_CredReadA();
801     test_CredWriteA();
802     test_CredDeleteA();
803 
804     test_CredReadDomainCredentialsA();
805 
806     trace("generic:\n");
807     if (persists[CRED_TYPE_GENERIC] == CRED_PERSIST_NONE)
808         skip("CRED_TYPE_GENERIC credentials are not supported or are disabled. Skipping\n");
809     else
810         test_generic();
811 
812         trace("domain password:\n");
813     if (persists[CRED_TYPE_DOMAIN_PASSWORD] == CRED_PERSIST_NONE)
814         skip("CRED_TYPE_DOMAIN_PASSWORD credentials are not supported or are disabled. Skipping\n");
815     else
816         test_domain_password(CRED_TYPE_DOMAIN_PASSWORD);
817 
818     trace("domain visible password:\n");
819     if (persists[CRED_TYPE_DOMAIN_VISIBLE_PASSWORD] == CRED_PERSIST_NONE)
820         skip("CRED_TYPE_DOMAIN_VISIBLE_PASSWORD credentials are not supported or are disabled. Skipping\n");
821     else
822         test_domain_password(CRED_TYPE_DOMAIN_VISIBLE_PASSWORD);
823 
824     test_CredMarshalCredentialA();
825     test_CredUnmarshalCredentialA();
826     test_CredIsMarshaledCredentialA();
827 }
828