From d5d2f01d3e8ed076ecf8f990210454047817fb72 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Thu, 8 Mar 2012 20:27:37 +0100 Subject: [PATCH] advapi32: Implement CredMarshalCredential and CredUnmarshalCredential. --- dlls/advapi32/advapi32.spec | 8 +- dlls/advapi32/cred.c | 261 +++++++++++++++++++++++++++++++ dlls/advapi32/tests/cred.c | 302 +++++++++++++++++++++++++++++++++++- include/wincred.h | 32 ++++ 4 files changed, 596 insertions(+), 7 deletions(-) diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index 5bf0a026adb..2b5db2ba33c 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -148,8 +148,8 @@ # @ stub CredIsMarshaledCredentialW # @ stub CredIsProtectedA # @ stub CredIsProtectedW -# @ stub CredMarshalCredentialA -# @ stub CredMarshalCredentialW +@ stdcall CredMarshalCredentialA(long ptr ptr) +@ stdcall CredMarshalCredentialW(long ptr ptr) # @ stub CredpConvertOneCredentialSize # @ stub CredpEncodeSecret @ stub CredProfileLoaded @@ -164,8 +164,8 @@ # @ stub CredRenameA # @ stub CredRenameW # @ stub CredRestoreCredentials -# @ stub CredUnmarshalCredentialA -# @ stub CredUnmarshalCredentialW +@ stdcall CredUnmarshalCredentialA(str ptr ptr) +@ stdcall CredUnmarshalCredentialW(wstr ptr ptr) # @ stub CredUnprotectA # @ stub CredUnprotectW @ stdcall CredWriteA(ptr long) diff --git a/dlls/advapi32/cred.c b/dlls/advapi32/cred.c index c7af18b20bb..432eb5c8570 100644 --- a/dlls/advapi32/cred.c +++ b/dlls/advapi32/cred.c @@ -1900,3 +1900,264 @@ WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists) } return TRUE; } + +/****************************************************************************** + * CredMarshalCredentialA [ADVAPI32.@] + */ +BOOL WINAPI CredMarshalCredentialA( CRED_MARSHAL_TYPE type, PVOID cred, LPSTR *out ) +{ + BOOL ret; + WCHAR *outW; + + TRACE("%u, %p, %p\n", type, cred, out); + + if ((ret = CredMarshalCredentialW( type, cred, &outW ))) + { + int len = WideCharToMultiByte( CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL ); + if (!(*out = HeapAlloc( GetProcessHeap(), 0, len ))) + { + HeapFree( GetProcessHeap(), 0, outW ); + return FALSE; + } + WideCharToMultiByte( CP_ACP, 0, outW, -1, *out, len, NULL, NULL ); + HeapFree( GetProcessHeap(), 0, outW ); + } + return ret; +} + +static UINT cred_encode( const char *bin, unsigned int len, WCHAR *cred ) +{ + static char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#-"; + UINT n = 0, x; + + while (len > 0) + { + cred[n++] = enc[bin[0] & 0x3f]; + x = (bin[0] & 0xc0) >> 6; + if (len == 1) + { + cred[n++] = enc[x]; + break; + } + cred[n++] = enc[((bin[1] & 0xf) << 2) | x]; + x = (bin[1] & 0xf0) >> 4; + if (len == 2) + { + cred[n++] = enc[x]; + break; + } + cred[n++] = enc[((bin[2] & 0x3) << 4) | x]; + cred[n++] = enc[(bin[2] & 0xfc) >> 2]; + bin += 3; + len -= 3; + } + return n; +} + +/****************************************************************************** + * CredMarshalCredentialW [ADVAPI32.@] + */ +BOOL WINAPI CredMarshalCredentialW( CRED_MARSHAL_TYPE type, PVOID cred, LPWSTR *out ) +{ + CERT_CREDENTIAL_INFO *cert = cred; + USERNAME_TARGET_CREDENTIAL_INFO *target = cred; + DWORD len, size; + WCHAR *p; + + TRACE("%u, %p, %p\n", type, cred, out); + + if (!cred || (type == CertCredential && cert->cbSize < sizeof(*cert)) || + (type != CertCredential && type != UsernameTargetCredential && type != BinaryBlobCredential) || + (type == UsernameTargetCredential && (!target->UserName || !target->UserName[0]))) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + switch (type) + { + case CertCredential: + { + char hash[CERT_HASH_LENGTH + 2]; + + memcpy( hash, cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert) ); + memset( hash + sizeof(cert->rgbHashOfCert), 0, sizeof(hash) - sizeof(cert->rgbHashOfCert) ); + + size = sizeof(hash) * 4 / 3; + if (!(p = HeapAlloc( GetProcessHeap(), 0, (size + 4) * sizeof(WCHAR) ))) return FALSE; + p[0] = '@'; + p[1] = '@'; + p[2] = 'A' + type; + len = cred_encode( (const char *)hash, sizeof(hash), p + 3 ); + p[len] = 0; + break; + } + case UsernameTargetCredential: + { + len = strlenW( target->UserName ); + size = (sizeof(DWORD) + len * sizeof(WCHAR) + 2) * 4 / 3; + if (!(p = HeapAlloc( GetProcessHeap(), 0, (size + 4) * sizeof(WCHAR) ))) return FALSE; + p[0] = '@'; + p[1] = '@'; + p[2] = 'A' + type; + size = len * sizeof(WCHAR); + len = cred_encode( (const char *)&size, sizeof(DWORD), p + 3 ); + len += cred_encode( (const char *)target->UserName, size, p + 3 + len ); + p[len + 3] = 0; + break; + } + case BinaryBlobCredential: + FIXME("BinaryBlobCredential not implemented\n"); + return FALSE; + default: + return FALSE; + } + *out = p; + return TRUE; +} + +/****************************************************************************** + * CredUnmarshalCredentialA [ADVAPI32.@] + */ +BOOL WINAPI CredUnmarshalCredentialA( LPCSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out ) +{ + BOOL ret; + WCHAR *credW = NULL; + + TRACE("%s, %p, %p\n", debugstr_a(cred), type, out); + + if (cred) + { + int len = MultiByteToWideChar( CP_ACP, 0, cred, -1, NULL, 0 ); + if (!(credW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE; + MultiByteToWideChar( CP_ACP, 0, cred, -1, credW, len ); + } + ret = CredUnmarshalCredentialW( credW, type, out ); + HeapFree( GetProcessHeap(), 0, credW ); + return ret; +} + +static inline char char_decode( WCHAR c ) +{ + if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '#') return 62; + if (c == '-') return 63; + return 64; +} + +static BOOL cred_decode( const WCHAR *cred, unsigned int len, char *buf ) +{ + unsigned int i = 0; + char c0, c1, c2, c3; + const WCHAR *p = cred; + + while (len >= 4) + { + if ((c0 = char_decode( p[0] )) > 63) return FALSE; + if ((c1 = char_decode( p[1] )) > 63) return FALSE; + if ((c2 = char_decode( p[2] )) > 63) return FALSE; + if ((c3 = char_decode( p[3] )) > 63) return FALSE; + + buf[i + 0] = (c1 << 6) | c0; + buf[i + 1] = (c2 << 4) | (c1 >> 2); + buf[i + 2] = (c3 << 2) | (c2 >> 4); + len -= 4; + i += 3; + p += 4; + } + if (len == 3) + { + if ((c0 = char_decode( p[0] )) > 63) return FALSE; + if ((c1 = char_decode( p[1] )) > 63) return FALSE; + if ((c2 = char_decode( p[2] )) > 63) return FALSE; + + buf[i + 0] = (c1 << 6) | c0; + buf[i + 1] = (c2 << 4) | (c1 >> 2); + buf[i + 2] = c2 >> 4; + } + else if (len == 2) + { + if ((c0 = char_decode( p[0] )) > 63) return FALSE; + if ((c1 = char_decode( p[1] )) > 63) return FALSE; + + buf[i + 0] = (c1 << 6) | c0; + buf[i + 1] = c1 >> 2; + buf[i + 2] = 0; + } + else if (len == 1) + { + if ((c0 = char_decode( p[0] )) > 63) return FALSE; + + buf[i + 0] = c0; + buf[i + 1] = 0; + buf[i + 2] = 0; + } + return TRUE; +} + +/****************************************************************************** + * CredUnmarshalCredentialW [ADVAPI32.@] + */ +BOOL WINAPI CredUnmarshalCredentialW( LPCWSTR cred, PCRED_MARSHAL_TYPE type, PVOID *out ) +{ + unsigned int len, buflen, size; + + TRACE("%s, %p, %p\n", debugstr_w(cred), type, out); + + if (!cred || cred[0] != '@' || cred[1] != '@' || !cred[2] || !cred[3]) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + len = strlenW( cred + 3 ); + switch (cred[2] - 'A') + { + case CertCredential: + { + char hash[CERT_HASH_LENGTH + 2]; + CERT_CREDENTIAL_INFO *cert; + + if (len != 27 || !cred_decode( cred + 3, len, hash )) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (!(cert = HeapAlloc( GetProcessHeap(), 0, sizeof(*cert) ))) return FALSE; + memcpy( cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert) ); + cert->cbSize = sizeof(*cert); + *type = CertCredential; + *out = cert; + break; + } + case UsernameTargetCredential: + { + USERNAME_TARGET_CREDENTIAL_INFO *target; + + if (len < 9 || !cred_decode( cred + 3, 6, (char *)&size ) || !size || size % sizeof(WCHAR)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + buflen = sizeof(*target) + size + sizeof(WCHAR); + if (!(target = HeapAlloc( GetProcessHeap(), 0, buflen ))) return FALSE; + if (!cred_decode( cred + 9, len - 6, (char *)(target + 1) )) + { + HeapFree( GetProcessHeap(), 0, target ); + return FALSE; + } + target->UserName = (WCHAR *)(target + 1); + target->UserName[size / sizeof(WCHAR)] = 0; + *type = UsernameTargetCredential; + *out = target; + break; + } + case BinaryBlobCredential: + FIXME("BinaryBlobCredential not implemented\n"); + return FALSE; + default: + WARN("unhandled type %u\n", cred[2] - 'A'); + return FALSE; + } + return TRUE; +} diff --git a/dlls/advapi32/tests/cred.c b/dlls/advapi32/tests/cred.c index c2d9027e1de..de03ed7e1ce 100644 --- a/dlls/advapi32/tests/cred.c +++ b/dlls/advapi32/tests/cred.c @@ -35,7 +35,8 @@ static BOOL (WINAPI *pCredReadA)(LPCSTR,DWORD,DWORD,PCREDENTIALA *); static BOOL (WINAPI *pCredRenameA)(LPCSTR,LPCSTR,DWORD,DWORD); static BOOL (WINAPI *pCredWriteA)(PCREDENTIALA,DWORD); static BOOL (WINAPI *pCredReadDomainCredentialsA)(PCREDENTIAL_TARGET_INFORMATIONA,DWORD,DWORD*,PCREDENTIALA**); - +static BOOL (WINAPI *pCredMarshalCredentialA)(CRED_MARSHAL_TYPE,PVOID,LPSTR *); +static BOOL (WINAPI *pCredUnmarshalCredentialA)(LPCSTR,PCRED_MARSHAL_TYPE,PVOID); #define TEST_TARGET_NAME "credtest.winehq.org" #define TEST_TARGET_NAME2 "credtest2.winehq.org" @@ -336,6 +337,297 @@ static void test_domain_password(DWORD cred_type) ok(ret, "CredDeleteA failed with error %d\n", GetLastError()); } +static void test_CredMarshalCredentialA(void) +{ + static WCHAR emptyW[] = {0}; + static WCHAR tW[] = {'t',0}; + static WCHAR teW[] = {'t','e',0}; + static WCHAR tesW[] = {'t','e','s',0}; + static WCHAR testW[] = {'t','e','s','t',0}; + static WCHAR test1W[] = {'t','e','s','t','1',0}; + CERT_CREDENTIAL_INFO cert; + USERNAME_TARGET_CREDENTIAL_INFO username; + DWORD error; + char *str; + BOOL ret; + + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( 0, NULL, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + memset( cert.rgbHashOfCert, 0, sizeof(cert.rgbHashOfCert) ); + cert.cbSize = sizeof(cert); + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( 0, &cert, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + str = (char *)0xdeadbeef; + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( 0, &cert, &str ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( str == (char *)0xdeadbeef, "got %p\n", str ); + + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( CertCredential, NULL, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + if (0) { /* crash */ + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( CertCredential, &cert, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + } + + cert.cbSize = 0; + str = (char *)0xdeadbeef; + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( str == (char *)0xdeadbeef, "got %p\n", str ); + + cert.cbSize = sizeof(cert) + 4; + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str ); + pCredFree( str ); + + cert.cbSize = sizeof(cert); + cert.rgbHashOfCert[0] = 2; + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@BCAAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str ); + pCredFree( str ); + + cert.rgbHashOfCert[0] = 255; + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@B-DAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str ); + pCredFree( str ); + + cert.rgbHashOfCert[0] = 1; + cert.rgbHashOfCert[1] = 1; + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@BBEAAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str ); + pCredFree( str ); + + cert.rgbHashOfCert[0] = 1; + cert.rgbHashOfCert[1] = 1; + cert.rgbHashOfCert[2] = 1; + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@BBEQAAAAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str ); + pCredFree( str ); + + memset( cert.rgbHashOfCert, 0, sizeof(cert.rgbHashOfCert) ); + cert.rgbHashOfCert[0] = 'W'; + cert.rgbHashOfCert[1] = 'i'; + cert.rgbHashOfCert[2] = 'n'; + cert.rgbHashOfCert[3] = 'e'; + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@BXlmblBAAAAAAAAAAAAAAAAAAAAA" ), "got %s\n", str ); + pCredFree( str ); + + memset( cert.rgbHashOfCert, 0xff, sizeof(cert.rgbHashOfCert) ); + str = NULL; + ret = pCredMarshalCredentialA( CertCredential, &cert, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@B--------------------------P" ), "got %s\n", str ); + pCredFree( str ); + + username.UserName = NULL; + str = (char *)0xdeadbeef; + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( str == (char *)0xdeadbeef, "got %p\n", str ); + + username.UserName = emptyW; + str = (char *)0xdeadbeef; + SetLastError( 0xdeadbeef ); + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + ok( str == (char *)0xdeadbeef, "got %p\n", str ); + + username.UserName = tW; + str = NULL; + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@CCAAAAA0BA" ), "got %s\n", str ); + pCredFree( str ); + + username.UserName = teW; + str = NULL; + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@CEAAAAA0BQZAA" ), "got %s\n", str ); + pCredFree( str ); + + username.UserName = tesW; + str = NULL; + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@CGAAAAA0BQZAMHA" ), "got %s\n", str ); + pCredFree( str ); + + username.UserName = testW; + str = NULL; + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@CIAAAAA0BQZAMHA0BA" ), "got %s\n", str ); + pCredFree( str ); + + username.UserName = test1W; + str = NULL; + ret = pCredMarshalCredentialA( UsernameTargetCredential, &username, &str ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( str != NULL, "str not set\n" ); + ok( !lstrcmpA( str, "@@CKAAAAA0BQZAMHA0BQMAA" ), "got %s\n", str ); + pCredFree( str ); +} + +static void test_CredUnmarshalCredentialA(void) +{ + static WCHAR tW[] = {'t',0}; + static WCHAR testW[] = {'t','e','s','t',0}; + CERT_CREDENTIAL_INFO *cert; + USERNAME_TARGET_CREDENTIAL_INFO *username; + CRED_MARSHAL_TYPE type; + unsigned int i; + DWORD error; + BOOL ret; + + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( NULL, NULL, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + cert = NULL; + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( NULL, NULL, (void **)&cert ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + type = 0; + cert = NULL; + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( NULL, &type, (void **)&cert ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + type = 0; + cert = NULL; + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( "", &type, (void **)&cert ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + if (0) { /* crash */ + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA", &type, NULL ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA", NULL, (void **)&cert ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + } + + type = 0; + cert = NULL; + ret = pCredUnmarshalCredentialA( "@@BAAAAAAAAAAAAAAAAAAAAAAAAAAA", &type, (void **)&cert ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( type == CertCredential, "got %u\n", type ); + ok( cert != NULL, "cert is NULL\n" ); + ok( cert->cbSize == sizeof(*cert), "wrong size %u\n", cert->cbSize ); + for (i = 0; i < sizeof(cert->rgbHashOfCert); i++) ok( !cert->rgbHashOfCert[i], "wrong data\n" ); + pCredFree( cert ); + + type = 0; + cert = NULL; + ret = pCredUnmarshalCredentialA( "@@BXlmblBAAAAAAAAAAAAAAAAAAAAA", &type, (void **)&cert ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( type == CertCredential, "got %u\n", type ); + ok( cert != NULL, "cert is NULL\n" ); + ok( cert->cbSize == sizeof(*cert), "wrong size %u\n", cert->cbSize ); + ok( cert->rgbHashOfCert[0] == 'W', "wrong data)\n" ); + ok( cert->rgbHashOfCert[1] == 'i', "wrong data\n" ); + ok( cert->rgbHashOfCert[2] == 'n', "wrong data\n" ); + ok( cert->rgbHashOfCert[3] == 'e', "wrong data\n" ); + for (i = 4; i < sizeof(cert->rgbHashOfCert); i++) ok( !cert->rgbHashOfCert[i], "wrong data\n" ); + pCredFree( cert ); + + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( "@@CAAAAAA", &type, (void **)&username ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + SetLastError( 0xdeadbeef ); + ret = pCredUnmarshalCredentialA( "@@CAAAAAA0BA", &type, (void **)&username ); + error = GetLastError(); + ok( !ret, "unexpected success\n" ); + ok( error == ERROR_INVALID_PARAMETER, "got %u\n", error ); + + type = 0; + username = NULL; + ret = pCredUnmarshalCredentialA( "@@CCAAAAA0BA", &type, (void **)&username ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( type == UsernameTargetCredential, "got %u\n", type ); + ok( username != NULL, "username is NULL\n" ); + ok( username->UserName != NULL, "UserName is NULL\n" ); + ok( !lstrcmpW( username->UserName, tW ), "got %s\n", wine_dbgstr_w(username->UserName) ); + pCredFree( username ); + + type = 0; + username = NULL; + ret = pCredUnmarshalCredentialA( "@@CIAAAAA0BQZAMHA0BA", &type, (void **)&username ); + ok( ret, "unexpected failure %u\n", GetLastError() ); + ok( type == UsernameTargetCredential, "got %u\n", type ); + ok( username != NULL, "username is NULL\n" ); + ok( username->UserName != NULL, "UserName is NULL\n" ); + ok( !lstrcmpW( username->UserName, testW ), "got %s\n", wine_dbgstr_w(username->UserName) ); + pCredFree( username ); +} + START_TEST(cred) { DWORD persists[CRED_TYPE_MAXIMUM]; @@ -348,9 +640,10 @@ START_TEST(cred) pCredReadA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadA"); pCredRenameA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredRenameA"); pCredReadDomainCredentialsA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadDomainCredentialsA"); + pCredMarshalCredentialA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredMarshalCredentialA"); + pCredUnmarshalCredentialA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredUnmarshalCredentialA"); - if (!pCredEnumerateA || !pCredFree || !pCredWriteA || !pCredDeleteA || - !pCredReadA) + if (!pCredEnumerateA || !pCredFree || !pCredWriteA || !pCredDeleteA || !pCredReadA) { win_skip("credentials functions not present in advapi32.dll\n"); return; @@ -392,4 +685,7 @@ START_TEST(cred) skip("CRED_TYPE_DOMAIN_VISIBLE_PASSWORD credentials are not supported or are disabled. Skipping\n"); else test_domain_password(CRED_TYPE_DOMAIN_VISIBLE_PASSWORD); + + test_CredMarshalCredentialA(); + test_CredUnmarshalCredentialA(); } diff --git a/include/wincred.h b/include/wincred.h index 59f248905d0..fb18a01b97f 100644 --- a/include/wincred.h +++ b/include/wincred.h @@ -150,6 +150,32 @@ typedef struct _CREDUI_INFOW DECL_WINELIB_TYPE_AW(CREDUI_INFO) DECL_WINELIB_TYPE_AW(PCREDUI_INFO) +typedef enum _CRED_MARSHAL_TYPE +{ + CertCredential = 1, + UsernameTargetCredential, + BinaryBlobCredential +} CRED_MARSHAL_TYPE, *PCRED_MARSHAL_TYPE; + +#define CERT_HASH_LENGTH 20 + +typedef struct _CERT_CREDENTIAL_INFO +{ + ULONG cbSize; + UCHAR rgbHashOfCert[CERT_HASH_LENGTH]; +} CERT_CREDENTIAL_INFO, *PCERT_CREDENTIAL_INFO; + +typedef struct _USERNAME_TARGET_CREDENTIAL_INFO +{ + LPWSTR UserName; +} USERNAME_TARGET_CREDENTIAL_INFO; + +typedef struct _BINARY_BLOB_CREDENTIAL_INFO +{ + ULONG cbBlob; + LPBYTE pbBlob; +} BINARY_BLOB_CREDENTIAL_INFO, *PBINARY_BLOB_CREDENTIAL_INFO; + #define CRED_MAX_STRING_LENGTH 256 #define CRED_MAX_USERNAME_LENGTH 513 #define CRED_MAX_GENERIC_TARGET_NAME_LENGTH 32767 @@ -222,6 +248,9 @@ WINADVAPI BOOL WINAPI CredEnumerateW(LPCWSTR,DWORD,DWORD *,PCREDENTIALW **); #define CredEnumerate WINELIB_NAME_AW(CredEnumerate) WINADVAPI VOID WINAPI CredFree(PVOID); WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD,LPDWORD); +WINADVAPI BOOL WINAPI CredMarshalCredentialA(CRED_MARSHAL_TYPE,PVOID,LPSTR *); +WINADVAPI BOOL WINAPI CredMarshalCredentialW(CRED_MARSHAL_TYPE,PVOID,LPWSTR *); +#define CredMarshalCredential WINELIB_NAME_AW(CredMarshalCredential) WINADVAPI BOOL WINAPI CredReadA(LPCSTR,DWORD,DWORD,PCREDENTIALA *); WINADVAPI BOOL WINAPI CredReadW(LPCWSTR,DWORD,DWORD,PCREDENTIALW *); #define CredRead WINELIB_NAME_AW(CredRead) @@ -231,6 +260,9 @@ WINADVAPI BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATION WINADVAPI BOOL WINAPI CredRenameA(LPCSTR,LPCSTR,DWORD,DWORD); WINADVAPI BOOL WINAPI CredRenameW(LPCWSTR,LPCWSTR,DWORD,DWORD); #define CredRename WINELIB_NAME_AW(CredRename) +WINADVAPI BOOL WINAPI CredUnmarshalCredentialA(LPCSTR,PCRED_MARSHAL_TYPE,PVOID *); +WINADVAPI BOOL WINAPI CredUnmarshalCredentialW(LPCWSTR,PCRED_MARSHAL_TYPE,PVOID *); +#define CredUnmarshalCredential WINELIB_NAME_AW(CredUnmarshalCredential) WINADVAPI BOOL WINAPI CredWriteA(PCREDENTIALA,DWORD); WINADVAPI BOOL WINAPI CredWriteW(PCREDENTIALW,DWORD); #define CredWrite WINELIB_NAME_AW(CredWrite)