diff --git a/dlls/credui/credui.spec b/dlls/credui/credui.spec index d32a6020365..891416c0039 100644 --- a/dlls/credui/credui.spec +++ b/dlls/credui/credui.spec @@ -15,3 +15,4 @@ @ stub DllGetClassObject @ stub DllRegisterServer @ stub DllUnregisterServer +@ stdcall SspiPromptForCredentialsW(wstr ptr long wstr ptr ptr ptr long) diff --git a/dlls/credui/credui_main.c b/dlls/credui/credui_main.c index c7b2da44039..beb3c586c92 100644 --- a/dlls/credui/credui_main.c +++ b/dlls/credui/credui_main.c @@ -25,6 +25,8 @@ #include "winnt.h" #include "winuser.h" #include "wincred.h" +#include "rpc.h" +#include "sspi.h" #include "commctrl.h" #include "credui_resources.h" @@ -558,7 +560,8 @@ static BOOL find_existing_credential(const WCHAR *target, WCHAR *username, ULONG if (!CredEnumerateW(target, 0, &count, &credentials)) return FALSE; for (i = 0; i < count; i++) { - if (credentials[i]->Type != CRED_TYPE_DOMAIN_PASSWORD) + if (credentials[i]->Type != CRED_TYPE_DOMAIN_PASSWORD && + credentials[i]->Type != CRED_TYPE_GENERIC) { FIXME("no support for type %u credentials\n", credentials[i]->Type); continue; @@ -849,3 +852,80 @@ BOOL WINAPI CredUIInitControls(void) FIXME("() stub\n"); return TRUE; } + +/****************************************************************************** + * SspiPromptForCredentialsW [CREDUI.@] + */ +ULONG SEC_ENTRY SspiPromptForCredentialsW( PCWSTR target, void *info, + DWORD error, PCWSTR package, + PSEC_WINNT_AUTH_IDENTITY_OPAQUE input_id, + PSEC_WINNT_AUTH_IDENTITY_OPAQUE *output_id, + BOOL *save, DWORD sspi_flags ) +{ + static const WCHAR basicW[] = {'B','a','s','i','c',0}; + static const WCHAR ntlmW[] = {'N','T','L','M',0}; + static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; + WCHAR username[CREDUI_MAX_USERNAME_LENGTH + 1] = {0}; + WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1] = {0}; + DWORD len_username = sizeof(username) / sizeof(username[0]); + DWORD len_password = sizeof(password) / sizeof(password[0]); + DWORD ret, flags; + CREDUI_INFOW *cred_info = info; + + FIXME( "(%s, %p, %u, %s, %p, %p, %p, %x) stub\n", debugstr_w(target), info, + error, debugstr_w(package), input_id, output_id, save, sspi_flags ); + + if (!target) return ERROR_INVALID_PARAMETER; + if (!package || (strcmpiW( package, basicW ) && strcmpiW( package, ntlmW ) && + strcmpiW( package, negotiateW ))) + { + FIXME( "package %s not supported\n", debugstr_w(package) ); + return ERROR_NO_SUCH_PACKAGE; + } + if (input_id) + { + FIXME( "input identity not supported\n" ); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + flags = CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS; + + if (sspi_flags & SSPIPFC_CREDPROV_DO_NOT_SAVE) + flags |= CREDUI_FLAGS_DO_NOT_PERSIST; + + if (!(sspi_flags & SSPIPFC_NO_CHECKBOX)) + flags |= CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX; + + find_existing_credential( target, username, len_username, password, len_password ); + + if (!(ret = CredUIPromptForCredentialsW( cred_info, target, NULL, error, username, + len_username, password, len_password, save, flags ))) + { + SEC_WINNT_AUTH_IDENTITY_W *id; + DWORD size = sizeof(*id); + WCHAR *ptr; + + len_username = strlenW( username ); + len_password = strlenW( password ); + + size += (len_username + 1) * sizeof(WCHAR); + size += (len_password + 1) * sizeof(WCHAR); + if (!(id = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_OUTOFMEMORY; + ptr = (WCHAR *)(id + 1); + + memcpy( ptr, username, (len_username + 1) * sizeof(WCHAR) ); + id->User = ptr; + id->UserLength = len_username; + ptr += len_username + 1; + id->Domain = NULL; + id->DomainLength = 0; + memcpy( ptr, password, (len_password + 1) * sizeof(WCHAR) ); + id->Password = ptr; + id->PasswordLength = len_password; + id->Flags = 0; + + *output_id = id; + } + + return ret; +} diff --git a/dlls/credui/tests/credui.c b/dlls/credui/tests/credui.c index 18fc5bc616f..1f5aa021541 100644 --- a/dlls/credui/tests/credui.c +++ b/dlls/credui/tests/credui.c @@ -23,9 +23,17 @@ #include "windef.h" #include "winbase.h" #include "wincred.h" +#include "sspi.h" #include "wine/test.h" +static SECURITY_STATUS (SEC_ENTRY *pSspiEncodeAuthIdentityAsStrings) + (PSEC_WINNT_AUTH_IDENTITY_OPAQUE,PCWSTR*,PCWSTR*,PCWSTR*); +static void (SEC_ENTRY *pSspiFreeAuthIdentity) + (PSEC_WINNT_AUTH_IDENTITY_OPAQUE); +static ULONG (SEC_ENTRY *pSspiPromptForCredentialsW) + (PCWSTR,void*,ULONG,PCWSTR,PSEC_WINNT_AUTH_IDENTITY_OPAQUE,PSEC_WINNT_AUTH_IDENTITY_OPAQUE*,int*,ULONG); + static void test_CredUIPromptForCredentials(void) { static const WCHAR wszServerName[] = {'W','i','n','e','T','e','s','t',0}; @@ -140,7 +148,71 @@ static void test_CredUIPromptForCredentials(void) } } +static void test_SspiPromptForCredentials(void) +{ + static const WCHAR targetW[] = {'S','s','p','i','T','e','s','t',0}; + static const WCHAR basicW[] = {'b','a','s','i','c',0}; + ULONG ret; + SECURITY_STATUS status; + CREDUI_INFOW info; + PSEC_WINNT_AUTH_IDENTITY_OPAQUE id; + const WCHAR *username, *domain, *creds; + int save; + + if (!pSspiPromptForCredentialsW || !pSspiFreeAuthIdentity) + { + win_skip( "SspiPromptForCredentialsW is missing\n" ); + return; + } + + info.cbSize = sizeof(info); + info.hwndParent = NULL; + info.pszMessageText = targetW; + info.pszCaptionText = basicW; + info.hbmBanner = NULL; + ret = pSspiPromptForCredentialsW( NULL, &info, 0, basicW, NULL, &id, &save, 0 ); + ok( ret == ERROR_INVALID_PARAMETER, "got %u\n", ret ); + + ret = pSspiPromptForCredentialsW( targetW, &info, 0, NULL, NULL, &id, &save, 0 ); + ok( ret == ERROR_NO_SUCH_PACKAGE, "got %u\n", ret ); + + if (winetest_interactive) + { + id = NULL; + save = -1; + ret = pSspiPromptForCredentialsW( targetW, &info, 0, basicW, NULL, &id, &save, 0 ); + ok( ret == ERROR_SUCCESS || ret == ERROR_CANCELLED, "got %u\n", ret ); + if (ret == ERROR_SUCCESS) + { + ok( id != NULL, "id not set\n" ); + ok( save == TRUE || save == FALSE, "got %d\n", save ); + + username = creds = NULL; + domain = (const WCHAR *)0xdeadbeef; + status = pSspiEncodeAuthIdentityAsStrings( id, &username, &domain, &creds ); + ok( status == SEC_E_OK, "got %u\n", status ); + ok( username != NULL, "username not set\n" ); + ok( domain == NULL, "domain not set\n" ); + ok( creds != NULL, "creds not set\n" ); + pSspiFreeAuthIdentity( id ); + } + } +} + START_TEST(credui) { + HMODULE hcredui = GetModuleHandleA( "credui.dll" ), hsecur32 = LoadLibraryA( "secur32.dll" ); + + if (hcredui) + pSspiPromptForCredentialsW = (void *)GetProcAddress( hcredui, "SspiPromptForCredentialsW" ); + if (hsecur32) + { + pSspiEncodeAuthIdentityAsStrings = (void *)GetProcAddress( hsecur32, "SspiEncodeAuthIdentityAsStrings" ); + pSspiFreeAuthIdentity = (void *)GetProcAddress( hsecur32, "SspiFreeAuthIdentity" ); + } + test_CredUIPromptForCredentials(); + test_SspiPromptForCredentials(); + + FreeLibrary( hsecur32 ); } diff --git a/include/wincred.h b/include/wincred.h index d0a75a72bfc..f238c0569cb 100644 --- a/include/wincred.h +++ b/include/wincred.h @@ -184,6 +184,7 @@ typedef struct _BINARY_BLOB_CREDENTIAL_INFO #define CRED_MAX_ATTRIBUTES 64 #define CRED_MAX_BLOB_SIZE 512 +#define CRED_MAX_CREDENTIAL_BLOB_SIZE (5 * CRED_MAX_BLOB_SIZE) #define CREDUI_MAX_MESSAGE_LENGTH 32767 #define CREDUI_MAX_CAPTION_LENGTH 128