From 0b21bb75a09051ed9a3d00a8c200d1118468bda1 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Wed, 24 Dec 2008 00:49:21 +0300 Subject: [PATCH] advapi32: Implement CredReadDomainCredentials stub and tests. --- dlls/advapi32/advapi32.spec | 4 +- dlls/advapi32/cred.c | 164 ++++++++++++++++++++++++++++++++++++ dlls/advapi32/tests/cred.c | 60 +++++++++++++ include/wincred.h | 39 +++++++++ 4 files changed, 265 insertions(+), 2 deletions(-) diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index 972ea7b8d14..3140f627a75 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -116,8 +116,8 @@ # @ stub CredMarshalCredentialW @ stub CredProfileLoaded @ stdcall CredReadA(str long long ptr) -# @ stub CredReadDomainCredentialsA -# @ stub CredReadDomainCredentialsW +@ stdcall CredReadDomainCredentialsA(ptr long ptr ptr) +@ stdcall CredReadDomainCredentialsW(ptr long ptr ptr) @ stdcall CredReadW(wstr long long ptr) # @ stub CredRenameA # @ stub CredRenameW diff --git a/dlls/advapi32/cred.c b/dlls/advapi32/cred.c index 1e51c4105a0..9ad4fb15862 100644 --- a/dlls/advapi32/cred.c +++ b/dlls/advapi32/cred.c @@ -1538,6 +1538,170 @@ BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW return TRUE; } +/****************************************************************************** + * CredReadDomainCredentialsA [ADVAPI32.@] + */ +BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA TargetInformation, + DWORD Flags, DWORD *Size, PCREDENTIALA **Credentials) +{ + PCREDENTIAL_TARGET_INFORMATIONW TargetInformationW; + DWORD len, i; + WCHAR *buffer, *end; + BOOL ret; + PCREDENTIALW* CredentialsW; + + TRACE("(%p, 0x%x, %p, %p)\n", TargetInformation, Flags, Size, Credentials); + + /* follow Windows behavior - do not test for NULL, initialize early */ + *Size = 0; + *Credentials = NULL; + + if (!TargetInformation) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + len = sizeof(*TargetInformationW); + if (TargetInformation->TargetName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, NULL, 0) * sizeof(WCHAR); + if (TargetInformation->NetbiosServerName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, NULL, 0) * sizeof(WCHAR); + if (TargetInformation->DnsServerName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, NULL, 0) * sizeof(WCHAR); + if (TargetInformation->NetbiosDomainName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, NULL, 0) * sizeof(WCHAR); + if (TargetInformation->DnsDomainName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, NULL, 0) * sizeof(WCHAR); + if (TargetInformation->DnsTreeName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, NULL, 0) * sizeof(WCHAR); + if (TargetInformation->PackageName) + len += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, NULL, 0) * sizeof(WCHAR); + + TargetInformationW = HeapAlloc(GetProcessHeap(), 0, len); + if (!TargetInformationW) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + buffer = (WCHAR*)(TargetInformationW + 1); + end = (WCHAR *)((char *)TargetInformationW + len); + + if (TargetInformation->TargetName) + { + TargetInformationW->TargetName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->TargetName, -1, + TargetInformationW->TargetName, end - buffer); + } else + TargetInformationW->TargetName = NULL; + + if (TargetInformation->NetbiosServerName) + { + TargetInformationW->NetbiosServerName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosServerName, -1, + TargetInformationW->NetbiosServerName, end - buffer); + } else + TargetInformationW->NetbiosServerName = NULL; + + if (TargetInformation->DnsServerName) + { + TargetInformationW->DnsServerName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsServerName, -1, + TargetInformationW->DnsServerName, end - buffer); + } else + TargetInformationW->DnsServerName = NULL; + + if (TargetInformation->NetbiosDomainName) + { + TargetInformationW->NetbiosDomainName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->NetbiosDomainName, -1, + TargetInformationW->NetbiosDomainName, end - buffer); + } else + TargetInformationW->NetbiosDomainName = NULL; + + if (TargetInformation->DnsDomainName) + { + TargetInformationW->DnsDomainName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsDomainName, -1, + TargetInformationW->DnsDomainName, end - buffer); + } else + TargetInformationW->DnsDomainName = NULL; + + if (TargetInformation->DnsTreeName) + { + TargetInformationW->DnsTreeName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->DnsTreeName, -1, + TargetInformationW->DnsTreeName, end - buffer); + } else + TargetInformationW->DnsTreeName = NULL; + + if (TargetInformation->PackageName) + { + TargetInformationW->PackageName = buffer; + buffer += MultiByteToWideChar(CP_ACP, 0, TargetInformation->PackageName, -1, + TargetInformationW->PackageName, end - buffer); + } else + TargetInformationW->PackageName = NULL; + + TargetInformationW->Flags = TargetInformation->Flags; + TargetInformationW->CredTypeCount = TargetInformation->CredTypeCount; + TargetInformationW->CredTypes = TargetInformation->CredTypes; + + ret = CredReadDomainCredentialsW(TargetInformationW, Flags, Size, &CredentialsW); + + HeapFree(GetProcessHeap(), 0, TargetInformationW); + + if (ret) + { + char *buf; + + len = *Size * sizeof(PCREDENTIALA); + for (i = 0; i < *Size; i++) + convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, &len); + + *Credentials = HeapAlloc(GetProcessHeap(), 0, len); + if (!*Credentials) + { + CredFree(CredentialsW); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + buf = (char *)&(*Credentials)[*Size]; + for (i = 0; i < *Size; i++) + { + len = 0; + (*Credentials)[i] = (PCREDENTIALA)buf; + convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], &len); + buf += len; + } + + CredFree(CredentialsW); + } + return ret; +} + +/****************************************************************************** + * CredReadDomainCredentialsW [ADVAPI32.@] + */ +BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW TargetInformation, DWORD Flags, + DWORD *Size, PCREDENTIALW **Credentials) +{ + FIXME("(%p, 0x%x, %p, %p) stub\n", TargetInformation, Flags, Size, Credentials); + + /* follow Windows behavior - do not test for NULL, initialize early */ + *Size = 0; + *Credentials = NULL; + if (!TargetInformation) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + SetLastError(ERROR_NOT_FOUND); + return FALSE; +} + /****************************************************************************** * CredWriteA [ADVAPI32.@] */ diff --git a/dlls/advapi32/tests/cred.c b/dlls/advapi32/tests/cred.c index df14439bc0f..30f505a7361 100644 --- a/dlls/advapi32/tests/cred.c +++ b/dlls/advapi32/tests/cred.c @@ -34,6 +34,8 @@ static BOOL (WINAPI *pCredGetSessionTypes)(DWORD,LPDWORD); 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**); + #define TEST_TARGET_NAME "credtest.winehq.org" #define TEST_TARGET_NAME2 "credtest2.winehq.org" @@ -136,6 +138,61 @@ static void test_CredDeleteA(void) GetLastError()); } +static void test_CredReadDomainCredentialsA(void) +{ + BOOL ret; + char target_name[] = "no_such_target"; + CREDENTIAL_TARGET_INFORMATIONA info = {target_name, NULL, target_name, NULL, NULL, NULL, NULL, 0, 0, NULL}; + DWORD count; + PCREDENTIAL* creds; + + if (!pCredReadDomainCredentialsA) + { + win_skip("CredReadDomainCredentialsA() is not implemented\n"); + return; + } + + /* these two tests would crash on both native and Wine. Implementations + * does not check for NULL output pointers and try to zero them out early */ +#if 0 + ok(!pCredReadDomainCredentialsA(&info, 0, NULL, &creds) && + GetLastError() == ERROR_INVALID_PARAMETER, "!"); + ok(!pCredReadDomainCredentialsA(&info, 0, &count, NULL) && + GetLastError() == ERROR_INVALID_PARAMETER, "!"); +#endif + + SetLastError(0xdeadbeef); + ret = pCredReadDomainCredentialsA(NULL, 0, &count, &creds); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "CredReadDomainCredentialsA should have failed with ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + creds = (void*)0x12345; + count = 2; + ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds); + ok(!ret && GetLastError() == ERROR_NOT_FOUND, + "CredReadDomainCredentialsA should have failed with ERROR_NOT_FOUND instead of %d\n", + GetLastError()); + ok(count ==0 && creds == NULL, "CredReadDomainCredentialsA must not return any result\n"); + + info.TargetName = NULL; + + SetLastError(0xdeadbeef); + ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds); + ok(!ret && GetLastError() == ERROR_NOT_FOUND, + "CredReadDomainCredentialsA should have failed with ERROR_NOT_FOUND instead of %d\n", + GetLastError()); + + info.DnsServerName = NULL; + + SetLastError(0xdeadbeef); + ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds); + ok(!ret && GetLastError() == ERROR_NOT_FOUND, + "CredReadDomainCredentialsA should have failed with ERROR_NOT_FOUND instead of %d\n", + GetLastError()); +} + static void check_blob(int line, DWORD cred_type, PCREDENTIALA cred) { if (cred_type == CRED_TYPE_DOMAIN_PASSWORD) @@ -279,6 +336,7 @@ START_TEST(cred) pCredDeleteA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredDeleteA"); pCredReadA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadA"); pCredRenameA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredRenameA"); + pCredReadDomainCredentialsA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadDomainCredentialsA"); if (!pCredEnumerateA || !pCredFree || !pCredWriteA || !pCredDeleteA || !pCredReadA) @@ -304,6 +362,8 @@ START_TEST(cred) test_CredWriteA(); test_CredDeleteA(); + test_CredReadDomainCredentialsA(); + trace("generic:\n"); if (persists[CRED_TYPE_GENERIC] == CRED_PERSIST_NONE) skip("CRED_TYPE_GENERIC credentials are not supported or are disabled. Skipping\n"); diff --git a/include/wincred.h b/include/wincred.h index 58650637118..59f248905d0 100644 --- a/include/wincred.h +++ b/include/wincred.h @@ -98,6 +98,37 @@ typedef struct _CREDENTIALW DECL_WINELIB_TYPE_AW(CREDENTIAL) DECL_WINELIB_TYPE_AW(PCREDENTIAL) +typedef struct _CREDENTIAL_TARGET_INFORMATIONA +{ + LPSTR TargetName; + LPSTR NetbiosServerName; + LPSTR DnsServerName; + LPSTR NetbiosDomainName; + LPSTR DnsDomainName; + LPSTR DnsTreeName; + LPSTR PackageName; + DWORD Flags; + DWORD CredTypeCount; + LPDWORD CredTypes; +} CREDENTIAL_TARGET_INFORMATIONA, *PCREDENTIAL_TARGET_INFORMATIONA; + +typedef struct _CREDENTIAL_TARGET_INFORMATIONW +{ + LPWSTR TargetName; + LPWSTR NetbiosServerName; + LPWSTR DnsServerName; + LPWSTR NetbiosDomainName; + LPWSTR DnsDomainName; + LPWSTR DnsTreeName; + LPWSTR PackageName; + DWORD Flags; + DWORD CredTypeCount; + LPDWORD CredTypes; +} CREDENTIAL_TARGET_INFORMATIONW, *PCREDENTIAL_TARGET_INFORMATIONW; + +DECL_WINELIB_TYPE_AW(CREDENTIAL_TARGET_INFORMATION) +DECL_WINELIB_TYPE_AW(PCREDENTIAL_TARGET_INFORMATION) + typedef struct _CREDUI_INFOA { DWORD cbSize; @@ -157,6 +188,11 @@ DECL_WINELIB_TYPE_AW(PCREDUI_INFO) #define CRED_PERSIST_LOCAL_MACHINE 2 #define CRED_PERSIST_ENTERPRISE 3 +/* values for CREDENTIAL_TARGET_INFORMATION::Flags */ +#define CRED_TI_SERVER_FORMAT_UNKNOWN 1 +#define CRED_TI_DOMAIN_FORMAT_UNKNOWN 2 +#define CRED_TI_ONLY_PASSWORD_REQUIRED 4 + #define CREDUI_FLAGS_INCORRECT_PASSWORD 0x00000001 #define CREDUI_FLAGS_DO_NOT_PERSIST 0x00000002 #define CREDUI_FLAGS_REQUEST_ADMINISTRATOR 0x00000004 @@ -189,6 +225,9 @@ WINADVAPI BOOL WINAPI CredGetSessionTypes(DWORD,LPDWORD); WINADVAPI BOOL WINAPI CredReadA(LPCSTR,DWORD,DWORD,PCREDENTIALA *); WINADVAPI BOOL WINAPI CredReadW(LPCWSTR,DWORD,DWORD,PCREDENTIALW *); #define CredRead WINELIB_NAME_AW(CredRead) +WINADVAPI BOOL WINAPI CredReadDomainCredentialsA(PCREDENTIAL_TARGET_INFORMATIONA,DWORD,DWORD *,PCREDENTIALA **); +WINADVAPI BOOL WINAPI CredReadDomainCredentialsW(PCREDENTIAL_TARGET_INFORMATIONW,DWORD,DWORD *,PCREDENTIALW **); +#define CredReadDomainCredentials WINELIB_NAME_AW(CredReadDomainCredentials) WINADVAPI BOOL WINAPI CredRenameA(LPCSTR,LPCSTR,DWORD,DWORD); WINADVAPI BOOL WINAPI CredRenameW(LPCWSTR,LPCWSTR,DWORD,DWORD); #define CredRename WINELIB_NAME_AW(CredRename)