/* * Wininet * * Copyright 2003 Mike McCormack for CodeWeavers Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #if defined(__MINGW32__) || defined (_MSC_VER) #include <ws2tcpip.h> #endif #include <stdarg.h> #include "windef.h" #include "winbase.h" #include "winuser.h" #include "winreg.h" #include "wininet.h" #include "winnetwk.h" #include "wine/debug.h" #include "winerror.h" #define NO_SHLWAPI_STREAM #include "shlwapi.h" #include "cryptuiapi.h" #include "internet.h" #include "wine/unicode.h" #include "resource.h" #define MAX_STRING_LEN 1024 WINE_DEFAULT_DEBUG_CHANNEL(wininet); struct WININET_ErrorDlgParams { http_request_t *req; HWND hWnd; DWORD dwError; DWORD dwFlags; LPVOID* lppvData; }; /*********************************************************************** * WININET_GetAuthRealm * * Determine the name of the (basic) Authentication realm */ static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz, BOOL proxy ) { LPWSTR p, q; DWORD index, query; static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 }; if (proxy) query = HTTP_QUERY_PROXY_AUTHENTICATE; else query = HTTP_QUERY_WWW_AUTHENTICATE; /* extract the Realm from the response and show it */ index = 0; if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) ) return FALSE; /* * FIXME: maybe we should check that we're * dealing with 'Basic' Authentication */ p = strchrW( szBuf, ' ' ); if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) ) { ERR("response wrong? (%s)\n", debugstr_w(szBuf)); return FALSE; } /* remove quotes */ p += 7; if( *p == '"' ) { p++; q = strrchrW( p, '"' ); if( q ) *q = 0; } strcpyW( szBuf, p ); return TRUE; } /* These two are not defined in the public headers */ extern DWORD WINAPI WNetCachePassword(LPSTR,WORD,LPSTR,WORD,BYTE,WORD); extern DWORD WINAPI WNetGetCachedPassword(LPSTR,WORD,LPSTR,LPWORD,BYTE); /*********************************************************************** * WININET_GetSetPassword */ static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, LPCWSTR szRealm, BOOL bSet ) { WCHAR szResource[0x80], szUserPass[0x40]; LPWSTR p; HWND hUserItem, hPassItem; DWORD r, dwMagic = 19; UINT r_len, u_len; WORD sz; static const WCHAR szColon[] = { ':',0 }; static const WCHAR szbs[] = { '/', 0 }; hUserItem = GetDlgItem( hdlg, IDC_USERNAME ); hPassItem = GetDlgItem( hdlg, IDC_PASSWORD ); /* now try fetch the username and password */ lstrcpyW( szResource, szServer); lstrcatW( szResource, szbs); lstrcatW( szResource, szRealm); /* * WNetCachePassword is only concerned with the length * of the data stored (which we tell it) and it does * not use strlen() internally so we can add WCHAR data * instead of ASCII data and get it back the same way. */ if( bSet ) { szUserPass[0] = 0; GetWindowTextW( hUserItem, szUserPass, (sizeof szUserPass-1)/sizeof(WCHAR) ); lstrcatW(szUserPass, szColon); u_len = strlenW( szUserPass ); GetWindowTextW( hPassItem, szUserPass+u_len, (sizeof szUserPass)/sizeof(WCHAR)-u_len ); r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR); u_len = (strlenW( szUserPass ) + 1)*sizeof(WCHAR); r = WNetCachePassword( (CHAR*)szResource, r_len, (CHAR*)szUserPass, u_len, dwMagic, 0 ); return ( r == WN_SUCCESS ); } sz = sizeof szUserPass; r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR); r = WNetGetCachedPassword( (CHAR*)szResource, r_len, (CHAR*)szUserPass, &sz, dwMagic ); if( r != WN_SUCCESS ) return FALSE; p = strchrW( szUserPass, ':' ); if( p ) { *p = 0; SetWindowTextW( hUserItem, szUserPass ); SetWindowTextW( hPassItem, p+1 ); } return TRUE; } /*********************************************************************** * WININET_SetAuthorization */ static BOOL WININET_SetAuthorization( http_request_t *request, LPWSTR username, LPWSTR password, BOOL proxy ) { http_session_t *session = request->session; LPWSTR p, q; p = heap_strdupW(username); if( !p ) return FALSE; q = heap_strdupW(password); if( !q ) { heap_free(p); return FALSE; } if (proxy) { appinfo_t *hIC = session->appInfo; heap_free(hIC->proxyUsername); hIC->proxyUsername = p; heap_free(hIC->proxyPassword); hIC->proxyPassword = q; } else { heap_free(session->userName); session->userName = p; heap_free(session->password); session->password = q; } return TRUE; } /*********************************************************************** * WININET_ProxyPasswordDialog */ static INT_PTR WINAPI WININET_ProxyPasswordDialog( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { HWND hitem; struct WININET_ErrorDlgParams *params; WCHAR szRealm[0x80], szServer[0x80]; if( uMsg == WM_INITDIALOG ) { TRACE("WM_INITDIALOG (%08lx)\n", lParam); /* save the parameter list */ params = (struct WININET_ErrorDlgParams*) lParam; SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); /* extract the Realm from the proxy response and show it */ if( WININET_GetAuthRealm( params->req->hdr.hInternet, szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); } hitem = GetDlgItem( hdlg, IDC_PROXY ); SetWindowTextW( hitem, params->req->session->appInfo->proxy ); WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); return TRUE; } params = (struct WININET_ErrorDlgParams*) GetWindowLongPtrW( hdlg, GWLP_USERDATA ); switch( uMsg ) { case WM_COMMAND: if( wParam == IDOK ) { WCHAR username[0x20], password[0x20]; username[0] = 0; hitem = GetDlgItem( hdlg, IDC_USERNAME ); if( hitem ) GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); password[0] = 0; hitem = GetDlgItem( hdlg, IDC_PASSWORD ); if( hitem ) GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && WININET_GetAuthRealm( params->req->hdr.hInternet, szRealm, sizeof szRealm/sizeof(WCHAR), TRUE) ) WININET_GetSetPassword( hdlg, params->req->session->appInfo->proxy, szRealm, TRUE ); WININET_SetAuthorization( params->req, username, password, TRUE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; } if( wParam == IDCANCEL ) { EndDialog( hdlg, 0 ); return TRUE; } break; } return FALSE; } /*********************************************************************** * WININET_PasswordDialog */ static INT_PTR WINAPI WININET_PasswordDialog( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { HWND hitem; struct WININET_ErrorDlgParams *params; WCHAR szRealm[0x80], szServer[0x80]; if( uMsg == WM_INITDIALOG ) { TRACE("WM_INITDIALOG (%08lx)\n", lParam); /* save the parameter list */ params = (struct WININET_ErrorDlgParams*) lParam; SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); /* extract the Realm from the response and show it */ if( WININET_GetAuthRealm( params->req->hdr.hInternet, szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); } hitem = GetDlgItem( hdlg, IDC_SERVER ); SetWindowTextW( hitem, params->req->session->hostName ); WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); return TRUE; } params = (struct WININET_ErrorDlgParams*) GetWindowLongPtrW( hdlg, GWLP_USERDATA ); switch( uMsg ) { case WM_COMMAND: if( wParam == IDOK ) { WCHAR username[0x20], password[0x20]; username[0] = 0; hitem = GetDlgItem( hdlg, IDC_USERNAME ); if( hitem ) GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); password[0] = 0; hitem = GetDlgItem( hdlg, IDC_PASSWORD ); if( hitem ) GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && WININET_GetAuthRealm( params->req->hdr.hInternet, szRealm, sizeof szRealm/sizeof(WCHAR), FALSE )) { WININET_GetSetPassword( hdlg, params->req->session->hostName, szRealm, TRUE ); } WININET_SetAuthorization( params->req, username, password, FALSE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; } if( wParam == IDCANCEL ) { EndDialog( hdlg, 0 ); return TRUE; } break; } 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 ) { http_request_t *req = params->req; DWORD flags, size = sizeof(flags); InternetQueryOptionW( req->hdr.hInternet, 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_REV_FAILED: flags |= SECURITY_FLAG_IGNORE_REVOCATION; break; case ERROR_INTERNET_SEC_CERT_ERRORS: if(flags & _SECURITY_FLAG_CERT_REV_FAILED) flags |= SECURITY_FLAG_IGNORE_REVOCATION; if(flags & _SECURITY_FLAG_CERT_INVALID_CA) flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; if(flags & _SECURITY_FLAG_CERT_INVALID_CN) flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; if(flags & _SECURITY_FLAG_CERT_INVALID_DATE) flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; break; } /* FIXME: Use helper function */ flags |= SECURITY_FLAG_SECURE; req->security_flags |= flags; if(is_valid_netconn(req->netconn)) req->netconn->security_flags |= flags; } 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; } /*********************************************************************** * InternetErrorDlg */ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, DWORD dwError, DWORD dwFlags, LPVOID* lppvData) { struct WININET_ErrorDlgParams params; http_request_t *req = NULL; DWORD res = ERROR_SUCCESS; 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; if(hRequest) { req = (http_request_t*)get_handle_object(hRequest); if(!req) return ERROR_INVALID_HANDLE; if(req->hdr.htype != WH_HHTTPREQ) return ERROR_SUCCESS; /* Yes, that was tested */ } params.req = req; params.hWnd = hWnd; params.dwError = dwError; params.dwFlags = dwFlags; params.lppvData = lppvData; switch( dwError ) { case ERROR_SUCCESS: case ERROR_INTERNET_INCORRECT_PASSWORD: { if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) break; if(!req) return ERROR_INVALID_HANDLE; switch(req->status_code) { case HTTP_STATUS_PROXY_AUTH_REQ: res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ), hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); break; case HTTP_STATUS_DENIED: res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ), hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); break; default: WARN("unhandled status %u\n", req->status_code); } break; } 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: case ERROR_INTERNET_SEC_CERT_REV_FAILED: if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) { res = ERROR_CANCELLED; break; } if(!req) return ERROR_INVALID_HANDLE; if( dwFlags & ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) FIXME("%08x contains unsupported flags.\n", dwFlags); res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ), hWnd, WININET_InvalidCertificateDialog, (LPARAM) ¶ms ); break; 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); res = ERROR_SUCCESS; break; default: res = ERROR_NOT_SUPPORTED; } if(req) WININET_Release(&req->hdr); return res; } /*********************************************************************** * InternetShowSecurityInfoByURLA (@) */ BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window) { FIXME("stub: %s %p\n", url, window); return FALSE; } /*********************************************************************** * InternetShowSecurityInfoByURLW (@) */ BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window) { FIXME("stub: %s %p\n", debugstr_w(url), window); return FALSE; } /*********************************************************************** * ShowX509EncodedCertificate (@) */ DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len) { PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING, cert, len); DWORD ret; if (certContext) { CRYPTUI_VIEWCERTIFICATE_STRUCTW view; memset(&view, 0, sizeof(view)); view.hwndParent = parent; view.pCertContext = certContext; if (CryptUIDlgViewCertificateW(&view, NULL)) ret = ERROR_SUCCESS; else ret = GetLastError(); CertFreeCertificateContext(certContext); } else ret = GetLastError(); return ret; }