diff --git a/dlls/wininet/dialogs.c b/dlls/wininet/dialogs.c index b3713a50b8c..4fd3d3fe212 100644 --- a/dlls/wininet/dialogs.c +++ b/dlls/wininet/dialogs.c @@ -44,6 +44,8 @@ #include "resource.h" +#define MAX_STRING_LEN 1024 + WINE_DEFAULT_DEBUG_CHANNEL(wininet); struct WININET_ErrorDlgParams @@ -460,6 +462,109 @@ static INT_PTR WINAPI WININET_PasswordDialog( return FALSE; } +/*********************************************************************** + * WININET_InvalidCertificateDialog + */ +static INT_PTR WINAPI WININET_InvalidCertificateDialog( + HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + struct WININET_ErrorDlgParams *params; + HWND hitem; + WCHAR buf[1024]; + + if( uMsg == WM_INITDIALOG ) + { + TRACE("WM_INITDIALOG (%08lx)\n", lParam); + + /* save the parameter list */ + params = (struct WININET_ErrorDlgParams*) lParam; + SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); + + switch( params->dwError ) + { + case ERROR_INTERNET_INVALID_CA: + LoadStringW( WININET_hModule, IDS_CERT_CA_INVALID, buf, 1024 ); + break; + case ERROR_INTERNET_SEC_CERT_DATE_INVALID: + LoadStringW( WININET_hModule, IDS_CERT_DATE_INVALID, buf, 1024 ); + break; + case ERROR_INTERNET_SEC_CERT_CN_INVALID: + LoadStringW( WININET_hModule, IDS_CERT_CN_INVALID, buf, 1024 ); + break; + case ERROR_INTERNET_SEC_CERT_ERRORS: + /* FIXME: We should fetch information about the + * certificate here and show all the relevant errors. + */ + LoadStringW( WININET_hModule, IDS_CERT_ERRORS, buf, 1024 ); + break; + default: + FIXME( "No message for error %d\n", params->dwError ); + buf[0] = '\0'; + } + + hitem = GetDlgItem( hdlg, IDC_CERT_ERROR ); + SetWindowTextW( hitem, buf ); + + return TRUE; + } + + params = (struct WININET_ErrorDlgParams*) + GetWindowLongPtrW( hdlg, GWLP_USERDATA ); + + switch( uMsg ) + { + case WM_COMMAND: + if( wParam == IDOK ) + { + BOOL res = TRUE; + + if( params->dwFlags & FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) + { + DWORD flags, size = sizeof(flags); + + InternetQueryOptionW( params->hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size ); + switch( params->dwError ) + { + case ERROR_INTERNET_INVALID_CA: + flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; + break; + case ERROR_INTERNET_SEC_CERT_DATE_INVALID: + flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; + break; + case ERROR_INTERNET_SEC_CERT_CN_INVALID: + flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + break; + case ERROR_INTERNET_SEC_CERT_ERRORS: + FIXME("Should only add ignore flags as needed.\n"); + flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID | + SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_UNKNOWN_CA; + /* FIXME: ERROR_INTERNET_SEC_CERT_ERRORS also + * seems to set the corresponding DLG_* flags. + */ + break; + } + res = InternetSetOptionW( params->hRequest, INTERNET_OPTION_SECURITY_FLAGS, &flags, size ); + if(!res) + WARN("InternetSetOption(INTERNET_OPTION_SECURITY_FLAGS) failed.\n"); + } + + EndDialog( hdlg, res ? ERROR_SUCCESS : ERROR_NOT_SUPPORTED ); + return TRUE; + } + if( wParam == IDCANCEL ) + { + TRACE("Pressed cancel.\n"); + + EndDialog( hdlg, ERROR_CANCELLED ); + return TRUE; + } + break; + } + + return FALSE; +} + /*********************************************************************** * WININET_GetConnectionStatus */ @@ -494,6 +599,9 @@ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData); + if( !hWnd && !(dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI) ) + return ERROR_INVALID_HANDLE; + params.hWnd = hWnd; params.hRequest = hRequest; params.dwError = dwError; @@ -520,14 +628,23 @@ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, WARN("unhandled status %u\n", dwStatus); return 0; } - - case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: - case ERROR_INTERNET_INVALID_CA: - case ERROR_INTERNET_POST_IS_NON_SECURE: + case ERROR_INTERNET_SEC_CERT_ERRORS: case ERROR_INTERNET_SEC_CERT_CN_INVALID: case ERROR_INTERNET_SEC_CERT_DATE_INVALID: + case ERROR_INTERNET_INVALID_CA: + if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) + return ERROR_CANCELLED; + + if( dwFlags & ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) + FIXME("%08x contains unsupported flags.\n", dwFlags); + + return DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ), + hWnd, WININET_InvalidCertificateDialog, (LPARAM) ¶ms ); + case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: + case ERROR_INTERNET_POST_IS_NON_SECURE: FIXME("Need to display dialog for error %d\n", dwError); return ERROR_SUCCESS; } - return ERROR_INVALID_PARAMETER; + + return ERROR_NOT_SUPPORTED; } diff --git a/dlls/wininet/resource.h b/dlls/wininet/resource.h index 279c1123db8..256a374af08 100644 --- a/dlls/wininet/resource.h +++ b/dlls/wininet/resource.h @@ -21,6 +21,7 @@ #include #include +#define IDD_INVCERTDLG 0x398 #define IDD_AUTHDLG 0x399 #define IDD_PROXYDLG 0x400 @@ -30,5 +31,10 @@ #define IDC_PASSWORD 0x404 #define IDC_SAVEPASSWORD 0x405 #define IDC_SERVER 0x406 +#define IDC_CERT_ERROR 0x407 #define IDS_LANCONNECTION 0x500 +#define IDS_CERT_CA_INVALID 0x501 +#define IDS_CERT_DATE_INVALID 0x502 +#define IDS_CERT_CN_INVALID 0x503 +#define IDS_CERT_ERRORS 0x504 diff --git a/dlls/wininet/tests/Makefile.in b/dlls/wininet/tests/Makefile.in index 942267a2788..2f585935a97 100644 --- a/dlls/wininet/tests/Makefile.in +++ b/dlls/wininet/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = wininet.dll -IMPORTS = wininet ws2_32 advapi32 +IMPORTS = wininet ws2_32 user32 advapi32 C_SRCS = \ ftp.c \ diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c index a38e196ecca..df0a88218ea 100644 --- a/dlls/wininet/tests/internet.c +++ b/dlls/wininet/tests/internet.c @@ -22,6 +22,7 @@ #include #include "windef.h" #include "winbase.h" +#include "winuser.h" #include "wininet.h" #include "winerror.h" #include "winreg.h" @@ -1123,6 +1124,152 @@ static void test_Option_PerConnectionOptionA(void) HeapFree(GetProcessHeap(), 0, list.pOptions); } +#define FLAG_TODO 0x1 +#define FLAG_NEEDREQ 0x2 +#define FLAG_UNIMPL 0x4 + +void test_InternetErrorDlg(void) +{ + HINTERNET ses, con, req; + DWORD res, flags; + HWND hwnd; + ULONG i; + static const struct { + DWORD error; + DWORD res; + DWORD test_flags; + } no_ui_res[] = { + { ERROR_INTERNET_INCORRECT_PASSWORD , ERROR_SUCCESS, FLAG_NEEDREQ }, + { ERROR_INTERNET_SEC_CERT_DATE_INVALID , ERROR_CANCELLED, 0 }, + { ERROR_INTERNET_SEC_CERT_CN_INVALID , ERROR_CANCELLED, 0 }, + { ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR , ERROR_SUCCESS, 0 }, + { ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR , ERROR_SUCCESS, FLAG_TODO }, + { ERROR_INTERNET_MIXED_SECURITY , ERROR_CANCELLED, FLAG_TODO }, + { ERROR_INTERNET_CHG_POST_IS_NON_SECURE , ERROR_CANCELLED, FLAG_TODO }, + { ERROR_INTERNET_POST_IS_NON_SECURE , ERROR_SUCCESS, 0 }, + { ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED, ERROR_CANCELLED, FLAG_NEEDREQ|FLAG_TODO }, + { ERROR_INTERNET_INVALID_CA , ERROR_CANCELLED, 0 }, + { ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR, ERROR_CANCELLED, FLAG_TODO }, + { ERROR_INTERNET_INSERT_CDROM , ERROR_CANCELLED, FLAG_TODO|FLAG_NEEDREQ|FLAG_UNIMPL }, + { ERROR_INTERNET_SEC_CERT_ERRORS , ERROR_CANCELLED, 0 }, + { ERROR_INTERNET_SEC_CERT_REV_FAILED , ERROR_CANCELLED, FLAG_TODO }, + { ERROR_HTTP_COOKIE_NEEDS_CONFIRMATION , ERROR_HTTP_COOKIE_DECLINED, FLAG_TODO }, + { ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT , ERROR_CANCELLED, FLAG_TODO }, + { ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT, ERROR_CANCELLED, FLAG_TODO }, + { ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION, ERROR_CANCELLED, FLAG_TODO }, + { ERROR_INTERNET_SEC_CERT_REVOKED , ERROR_CANCELLED, 0 }, + { 0, ERROR_NOT_SUPPORTED } + }; + + flags = 0; + + res = InternetErrorDlg(NULL, NULL, 12055, flags, NULL); + ok(res == ERROR_INVALID_HANDLE, "Got %d\n", res); + + ses = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(ses != 0, "InternetOpen failed: 0x%08x\n", GetLastError()); + con = InternetConnect(ses, "www.winehq.org", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(con != 0, "InternetConnect failed: 0x%08x\n", GetLastError()); + req = HttpOpenRequest(con, "GET", "/", NULL, NULL, NULL, 0, 0); + ok(req != 0, "HttpOpenRequest failed: 0x%08x\n", GetLastError()); + + /* NULL hwnd and FLAGS_ERROR_UI_FLAGS_NO_UI not set */ + for(i = INTERNET_ERROR_BASE; i < INTERNET_ERROR_LAST; i++) + { + res = InternetErrorDlg(NULL, req, i, flags, NULL); + ok(res == ERROR_INVALID_HANDLE, "Got %d (%d)\n", res, i); + } + + hwnd = GetDesktopWindow(); + ok(hwnd != NULL, "GetDesktopWindow failed (%d)\n", GetLastError()); + + flags = FLAGS_ERROR_UI_FLAGS_NO_UI; + for(i = INTERNET_ERROR_BASE; i < INTERNET_ERROR_LAST; i++) + { + DWORD expected, test_flags, j; + + for(j = 0; no_ui_res[j].error != 0; ++j) + if(no_ui_res[j].error == i) + break; + + test_flags = no_ui_res[j].test_flags; + expected = no_ui_res[j].res; + + /* Try an invalid request handle */ + res = InternetErrorDlg(hwnd, (HANDLE)0xdeadbeef, i, flags, NULL); + if(res == ERROR_CALL_NOT_IMPLEMENTED) + { + todo_wine ok(test_flags & FLAG_UNIMPL, "%i is unexpectedly unimplemented.\n", i); + continue; + } + else + todo_wine ok(res == ERROR_INVALID_HANDLE, "Got %d (%d)\n", res, i); + + /* With a valid req */ + if(i == ERROR_INTERNET_NEED_UI) + continue; /* Crashes on windows XP */ + + if(i == ERROR_INTERNET_SEC_CERT_REVOKED) + continue; /* Interactive (XP, Win7) */ + + res = InternetErrorDlg(hwnd, req, i, flags, NULL); + + /* Handle some special cases */ + switch(i) + { + case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: + case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR: + if(res == ERROR_CANCELLED) + { + /* Some windows XP, w2k3 x64, W2K8 */ + win_skip("Skipping some tests for %d\n", i); + continue; + } + break; + case 12054: /* ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED */ + if(res != expected) + { + /* Windows XP, W2K3 */ + ok(res == NTE_PROV_TYPE_NOT_DEF, "Got %d\n", res); + win_skip("Skipping some tests for %d\n", i); + continue; + } + break; + default: break; + } + + if(test_flags & FLAG_TODO) + todo_wine ok(res == expected, "Got %d, expected %d (%d)\n", res, expected, i); + else + ok(res == expected, "Got %d, expected %d (%d)\n", res, expected, i); + + /* Same thing with NULL hwnd */ + res = InternetErrorDlg(NULL, req, i, flags, NULL); + if(test_flags & FLAG_TODO) + todo_wine ok(res == expected, "Got %d, expected %d (%d)\n", res, expected, i); + else + ok(res == expected, "Got %d, expected %d (%d)\n", res, expected, i); + + + /* With a null req */ + if(test_flags & FLAG_NEEDREQ) + expected = ERROR_INVALID_PARAMETER; + + res = InternetErrorDlg(hwnd, NULL, i, flags, NULL); + if( test_flags & FLAG_TODO || i == ERROR_INTERNET_INCORRECT_PASSWORD) + todo_wine ok(res == expected, "Got %d, expected %d (%d)\n", res, expected, i); + else + ok(res == expected, "Got %d, expected %d (%d)\n", res, expected, i); + } + + res = InternetCloseHandle(req); + ok(res == TRUE, "InternetCloseHandle failed: 0x%08x\n", GetLastError()); + res = InternetCloseHandle(con); + ok(res == TRUE, "InternetCloseHandle failed: 0x%08x\n", GetLastError()); + res = InternetCloseHandle(ses); + ok(res == TRUE, "InternetCloseHandle failed: 0x%08x\n", GetLastError()); +} + /* ############################### */ START_TEST(internet) @@ -1153,6 +1300,7 @@ START_TEST(internet) test_null(); test_Option_PerConnectionOption(); test_Option_PerConnectionOptionA(); + test_InternetErrorDlg(); if (!pInternetTimeFromSystemTimeA) win_skip("skipping the InternetTime tests\n"); diff --git a/dlls/wininet/wininet_En.rc b/dlls/wininet/wininet_En.rc index d4ad2757083..5566859a548 100644 --- a/dlls/wininet/wininet_En.rc +++ b/dlls/wininet/wininet_En.rc @@ -60,7 +60,23 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_INVCERTDLG DIALOG 3, 24, 250, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Security Warning" +FONT 8, "MS Shell Dlg" +{ + LTEXT "There is a problem with the certificate for this site.", -1, 40, 6, 200, 20 + LTEXT "", IDC_CERT_ERROR, 40, 26, 200, 20 + LTEXT "Do you want to continue anyway?", -1, 40, 46, 200, 20 + PUSHBUTTON "Yes", IDOK, 40, 66, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "No", IDCANCEL, 100, 66, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE { IDS_LANCONNECTION "LAN Connection" + IDS_CERT_CA_INVALID "The certificate is issued by an unknown or untrusted publisher." + IDS_CERT_DATE_INVALID "The date on the certificate is invalid." + IDS_CERT_CN_INVALID "The name on the certificate does not match the site." + IDS_CERT_ERRORS "There is at least one unspecified security problem with this certificate." } diff --git a/dlls/wininet/wininet_Sv.rc b/dlls/wininet/wininet_Sv.rc index 520cdcb43d5..cc97d6e4d7f 100644 --- a/dlls/wininet/wininet_Sv.rc +++ b/dlls/wininet/wininet_Sv.rc @@ -60,7 +60,23 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_INVCERTDLG DIALOG 3, 24, 250, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Säkerhetsvarning" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Ett problem upptäcktes med certifikatet för denna site.", -1, 40, 6, 200, 20 + LTEXT "", IDC_CERT_ERROR, 40, 26, 200, 20 + LTEXT "Vill du fortsätta ändå?", -1, 40, 46, 200, 20 + PUSHBUTTON "Ja", IDOK, 40, 66, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Nej", IDCANCEL, 100, 66, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE { IDS_LANCONNECTION "LAN-anslutning" + IDS_CERT_CA_INVALID "Certifikatet är utfärdat av en okänd eller ej betrodd utgivare." + IDS_CERT_DATE_INVALID "Certifikatets datum är ogiltigt." + IDS_CERT_CN_INVALID "Namnet på certifikatet matchar inte sitens namn." + IDS_CERT_ERRORS "Certifikatet har minst ett ospecificerat säkerhetsproblem." }