1 /* 2 * Wininet 3 * 4 * Copyright 2003 Mike McCormack for CodeWeavers Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "ws2tcpip.h" 22 23 #include <stdarg.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winuser.h" 28 #include "winreg.h" 29 #include "wininet.h" 30 #include "winnetwk.h" 31 #include "wine/debug.h" 32 #include "winerror.h" 33 #define NO_SHLWAPI_STREAM 34 #include "shlwapi.h" 35 #include "cryptuiapi.h" 36 37 #include "internet.h" 38 39 #include "wine/unicode.h" 40 41 #include "resource.h" 42 43 #define MAX_STRING_LEN 1024 44 45 WINE_DEFAULT_DEBUG_CHANNEL(wininet); 46 47 struct WININET_ErrorDlgParams 48 { 49 http_request_t *req; 50 HWND hWnd; 51 DWORD dwError; 52 DWORD dwFlags; 53 LPVOID* lppvData; 54 }; 55 56 /*********************************************************************** 57 * WININET_GetAuthRealm 58 * 59 * Determine the name of the (basic) Authentication realm 60 */ 61 static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz, BOOL proxy ) 62 { 63 LPWSTR p, q; 64 DWORD index, query; 65 static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 }; 66 67 if (proxy) 68 query = HTTP_QUERY_PROXY_AUTHENTICATE; 69 else 70 query = HTTP_QUERY_WWW_AUTHENTICATE; 71 72 /* extract the Realm from the response and show it */ 73 index = 0; 74 if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) ) 75 return FALSE; 76 77 /* 78 * FIXME: maybe we should check that we're 79 * dealing with 'Basic' Authentication 80 */ 81 p = strchrW( szBuf, ' ' ); 82 if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) ) 83 { 84 ERR("response wrong? (%s)\n", debugstr_w(szBuf)); 85 return FALSE; 86 } 87 88 /* remove quotes */ 89 p += 7; 90 if( *p == '"' ) 91 { 92 p++; 93 q = strrchrW( p, '"' ); 94 if( q ) 95 *q = 0; 96 } 97 strcpyW( szBuf, p ); 98 99 return TRUE; 100 } 101 102 /* These two are not defined in the public headers */ 103 extern DWORD WINAPI WNetCachePassword(LPSTR,WORD,LPSTR,WORD,BYTE,WORD); 104 extern DWORD WINAPI WNetGetCachedPassword(LPSTR,WORD,LPSTR,LPWORD,BYTE); 105 106 /*********************************************************************** 107 * WININET_GetSetPassword 108 */ 109 static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, 110 LPCWSTR szRealm, BOOL bSet ) 111 { 112 WCHAR szResource[0x80], szUserPass[0x40]; 113 LPWSTR p; 114 HWND hUserItem, hPassItem; 115 DWORD r, dwMagic = 19; 116 UINT r_len, u_len; 117 WORD sz; 118 static const WCHAR szColon[] = { ':',0 }; 119 static const WCHAR szbs[] = { '/', 0 }; 120 121 hUserItem = GetDlgItem( hdlg, IDC_USERNAME ); 122 hPassItem = GetDlgItem( hdlg, IDC_PASSWORD ); 123 124 /* now try fetch the username and password */ 125 lstrcpyW( szResource, szServer); 126 lstrcatW( szResource, szbs); 127 lstrcatW( szResource, szRealm); 128 129 /* 130 * WNetCachePassword is only concerned with the length 131 * of the data stored (which we tell it) and it does 132 * not use strlen() internally so we can add WCHAR data 133 * instead of ASCII data and get it back the same way. 134 */ 135 if( bSet ) 136 { 137 szUserPass[0] = 0; 138 GetWindowTextW( hUserItem, szUserPass, ARRAY_SIZE( szUserPass ) - 1 ); 139 lstrcatW(szUserPass, szColon); 140 u_len = strlenW( szUserPass ); 141 GetWindowTextW( hPassItem, szUserPass+u_len, ARRAY_SIZE( szUserPass ) - u_len ); 142 143 r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR); 144 u_len = (strlenW( szUserPass ) + 1)*sizeof(WCHAR); 145 r = WNetCachePassword( (CHAR*)szResource, r_len, 146 (CHAR*)szUserPass, u_len, dwMagic, 0 ); 147 148 return ( r == WN_SUCCESS ); 149 } 150 151 sz = sizeof szUserPass; 152 r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR); 153 r = WNetGetCachedPassword( (CHAR*)szResource, r_len, 154 (CHAR*)szUserPass, &sz, dwMagic ); 155 if( r != WN_SUCCESS ) 156 return FALSE; 157 158 p = strchrW( szUserPass, ':' ); 159 if( p ) 160 { 161 *p = 0; 162 SetWindowTextW( hUserItem, szUserPass ); 163 SetWindowTextW( hPassItem, p+1 ); 164 } 165 166 return TRUE; 167 } 168 169 /*********************************************************************** 170 * WININET_SetAuthorization 171 */ 172 static BOOL WININET_SetAuthorization( http_request_t *request, LPWSTR username, 173 LPWSTR password, BOOL proxy ) 174 { 175 http_session_t *session = request->session; 176 LPWSTR p, q; 177 178 p = heap_strdupW(username); 179 if( !p ) 180 return FALSE; 181 182 q = heap_strdupW(password); 183 if( !q ) 184 { 185 heap_free(p); 186 return FALSE; 187 } 188 189 if (proxy) 190 { 191 appinfo_t *hIC = session->appInfo; 192 193 heap_free(hIC->proxyUsername); 194 hIC->proxyUsername = p; 195 196 heap_free(hIC->proxyPassword); 197 hIC->proxyPassword = q; 198 } 199 else 200 { 201 heap_free(session->userName); 202 session->userName = p; 203 204 heap_free(session->password); 205 session->password = q; 206 } 207 208 return TRUE; 209 } 210 211 /*********************************************************************** 212 * WININET_ProxyPasswordDialog 213 */ 214 static INT_PTR WINAPI WININET_ProxyPasswordDialog( 215 HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 216 { 217 HWND hitem; 218 struct WININET_ErrorDlgParams *params; 219 WCHAR szRealm[0x80]; 220 221 if( uMsg == WM_INITDIALOG ) 222 { 223 TRACE("WM_INITDIALOG (%08lx)\n", lParam); 224 225 /* save the parameter list */ 226 params = (struct WININET_ErrorDlgParams*) lParam; 227 SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); 228 229 /* extract the Realm from the proxy response and show it */ 230 if( WININET_GetAuthRealm( params->req->hdr.hInternet, 231 szRealm, ARRAY_SIZE( szRealm ), TRUE ) ) 232 { 233 hitem = GetDlgItem( hdlg, IDC_REALM ); 234 SetWindowTextW( hitem, szRealm ); 235 } 236 237 hitem = GetDlgItem( hdlg, IDC_PROXY ); 238 SetWindowTextW( hitem, params->req->session->appInfo->proxy ); 239 240 WININET_GetSetPassword( hdlg, params->req->session->appInfo->proxy, szRealm, FALSE ); 241 242 return TRUE; 243 } 244 245 params = (struct WININET_ErrorDlgParams*) 246 GetWindowLongPtrW( hdlg, GWLP_USERDATA ); 247 248 switch( uMsg ) 249 { 250 case WM_COMMAND: 251 if( wParam == IDOK ) 252 { 253 WCHAR username[0x20], password[0x20]; 254 255 username[0] = 0; 256 hitem = GetDlgItem( hdlg, IDC_USERNAME ); 257 if( hitem ) 258 GetWindowTextW( hitem, username, ARRAY_SIZE( username )); 259 260 password[0] = 0; 261 hitem = GetDlgItem( hdlg, IDC_PASSWORD ); 262 if( hitem ) 263 GetWindowTextW( hitem, password, ARRAY_SIZE( password )); 264 265 hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); 266 if( hitem && 267 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && 268 WININET_GetAuthRealm( params->req->hdr.hInternet, 269 szRealm, ARRAY_SIZE( szRealm ), TRUE) ) 270 WININET_GetSetPassword( hdlg, params->req->session->appInfo->proxy, szRealm, TRUE ); 271 WININET_SetAuthorization( params->req, username, password, TRUE ); 272 273 EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); 274 return TRUE; 275 } 276 if( wParam == IDCANCEL ) 277 { 278 EndDialog( hdlg, 0 ); 279 return TRUE; 280 } 281 break; 282 } 283 return FALSE; 284 } 285 286 /*********************************************************************** 287 * WININET_PasswordDialog 288 */ 289 static INT_PTR WINAPI WININET_PasswordDialog( 290 HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 291 { 292 HWND hitem; 293 struct WININET_ErrorDlgParams *params; 294 WCHAR szRealm[0x80]; 295 296 if( uMsg == WM_INITDIALOG ) 297 { 298 TRACE("WM_INITDIALOG (%08lx)\n", lParam); 299 300 /* save the parameter list */ 301 params = (struct WININET_ErrorDlgParams*) lParam; 302 SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); 303 304 /* extract the Realm from the response and show it */ 305 if( WININET_GetAuthRealm( params->req->hdr.hInternet, 306 szRealm, ARRAY_SIZE( szRealm ), FALSE ) ) 307 { 308 hitem = GetDlgItem( hdlg, IDC_REALM ); 309 SetWindowTextW( hitem, szRealm ); 310 } 311 312 hitem = GetDlgItem( hdlg, IDC_SERVER ); 313 SetWindowTextW( hitem, params->req->session->hostName ); 314 315 WININET_GetSetPassword( hdlg, params->req->session->hostName, szRealm, FALSE ); 316 317 return TRUE; 318 } 319 320 params = (struct WININET_ErrorDlgParams*) 321 GetWindowLongPtrW( hdlg, GWLP_USERDATA ); 322 323 switch( uMsg ) 324 { 325 case WM_COMMAND: 326 if( wParam == IDOK ) 327 { 328 WCHAR username[0x20], password[0x20]; 329 330 username[0] = 0; 331 hitem = GetDlgItem( hdlg, IDC_USERNAME ); 332 if( hitem ) 333 GetWindowTextW( hitem, username, ARRAY_SIZE( username )); 334 335 password[0] = 0; 336 hitem = GetDlgItem( hdlg, IDC_PASSWORD ); 337 if( hitem ) 338 GetWindowTextW( hitem, password, ARRAY_SIZE( password )); 339 340 hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); 341 if( hitem && 342 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && 343 WININET_GetAuthRealm( params->req->hdr.hInternet, 344 szRealm, ARRAY_SIZE( szRealm ), FALSE )) 345 { 346 WININET_GetSetPassword( hdlg, params->req->session->hostName, szRealm, TRUE ); 347 } 348 WININET_SetAuthorization( params->req, username, password, FALSE ); 349 350 EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); 351 return TRUE; 352 } 353 if( wParam == IDCANCEL ) 354 { 355 EndDialog( hdlg, 0 ); 356 return TRUE; 357 } 358 break; 359 } 360 return FALSE; 361 } 362 363 /*********************************************************************** 364 * WININET_InvalidCertificateDialog 365 */ 366 static INT_PTR WINAPI WININET_InvalidCertificateDialog( 367 HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 368 { 369 struct WININET_ErrorDlgParams *params; 370 HWND hitem; 371 WCHAR buf[1024]; 372 373 if( uMsg == WM_INITDIALOG ) 374 { 375 TRACE("WM_INITDIALOG (%08lx)\n", lParam); 376 377 /* save the parameter list */ 378 params = (struct WININET_ErrorDlgParams*) lParam; 379 SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); 380 381 switch( params->dwError ) 382 { 383 case ERROR_INTERNET_INVALID_CA: 384 LoadStringW( WININET_hModule, IDS_CERT_CA_INVALID, buf, 1024 ); 385 break; 386 case ERROR_INTERNET_SEC_CERT_DATE_INVALID: 387 LoadStringW( WININET_hModule, IDS_CERT_DATE_INVALID, buf, 1024 ); 388 break; 389 case ERROR_INTERNET_SEC_CERT_CN_INVALID: 390 LoadStringW( WININET_hModule, IDS_CERT_CN_INVALID, buf, 1024 ); 391 break; 392 case ERROR_INTERNET_SEC_CERT_ERRORS: 393 /* FIXME: We should fetch information about the 394 * certificate here and show all the relevant errors. 395 */ 396 LoadStringW( WININET_hModule, IDS_CERT_ERRORS, buf, 1024 ); 397 break; 398 default: 399 FIXME( "No message for error %d\n", params->dwError ); 400 buf[0] = '\0'; 401 } 402 403 hitem = GetDlgItem( hdlg, IDC_CERT_ERROR ); 404 SetWindowTextW( hitem, buf ); 405 406 return TRUE; 407 } 408 409 params = (struct WININET_ErrorDlgParams*) 410 GetWindowLongPtrW( hdlg, GWLP_USERDATA ); 411 412 switch( uMsg ) 413 { 414 case WM_COMMAND: 415 if( wParam == IDOK ) 416 { 417 if( params->dwFlags & FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) 418 { 419 http_request_t *req = params->req; 420 DWORD flags, size = sizeof(flags); 421 422 InternetQueryOptionW( req->hdr.hInternet, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size ); 423 switch( params->dwError ) 424 { 425 case ERROR_INTERNET_INVALID_CA: 426 flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; 427 break; 428 case ERROR_INTERNET_SEC_CERT_DATE_INVALID: 429 flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 430 break; 431 case ERROR_INTERNET_SEC_CERT_CN_INVALID: 432 flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; 433 break; 434 case ERROR_INTERNET_SEC_CERT_REV_FAILED: 435 flags |= SECURITY_FLAG_IGNORE_REVOCATION; 436 break; 437 case ERROR_INTERNET_SEC_CERT_ERRORS: 438 if(flags & _SECURITY_FLAG_CERT_REV_FAILED) 439 flags |= SECURITY_FLAG_IGNORE_REVOCATION; 440 if(flags & _SECURITY_FLAG_CERT_INVALID_CA) 441 flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; 442 if(flags & _SECURITY_FLAG_CERT_INVALID_CN) 443 flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; 444 if(flags & _SECURITY_FLAG_CERT_INVALID_DATE) 445 flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 446 break; 447 } 448 /* FIXME: Use helper function */ 449 flags |= SECURITY_FLAG_SECURE; 450 req->security_flags |= flags; 451 if(is_valid_netconn(req->netconn)) 452 req->netconn->security_flags |= flags; 453 } 454 455 EndDialog( hdlg, ERROR_SUCCESS ); 456 return TRUE; 457 } 458 if( wParam == IDCANCEL ) 459 { 460 TRACE("Pressed cancel.\n"); 461 462 EndDialog( hdlg, ERROR_CANCELLED ); 463 return TRUE; 464 } 465 break; 466 } 467 468 return FALSE; 469 } 470 471 /*********************************************************************** 472 * InternetErrorDlg 473 */ 474 DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, 475 DWORD dwError, DWORD dwFlags, LPVOID* lppvData) 476 { 477 struct WININET_ErrorDlgParams params; 478 http_request_t *req = NULL; 479 DWORD res = ERROR_SUCCESS; 480 481 TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData); 482 483 if( !hWnd && !(dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI) ) 484 return ERROR_INVALID_HANDLE; 485 486 if(hRequest) { 487 req = (http_request_t*)get_handle_object(hRequest); 488 if(!req) 489 return ERROR_INVALID_HANDLE; 490 if(req->hdr.htype != WH_HHTTPREQ) 491 return ERROR_SUCCESS; /* Yes, that was tested */ 492 } 493 494 params.req = req; 495 params.hWnd = hWnd; 496 params.dwError = dwError; 497 params.dwFlags = dwFlags; 498 params.lppvData = lppvData; 499 500 switch( dwError ) 501 { 502 case ERROR_SUCCESS: 503 case ERROR_INTERNET_INCORRECT_PASSWORD: { 504 if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) 505 break; 506 if(!req) 507 return ERROR_INVALID_HANDLE; 508 509 switch(req->status_code) { 510 case HTTP_STATUS_PROXY_AUTH_REQ: 511 res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ), 512 hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); 513 break; 514 case HTTP_STATUS_DENIED: 515 res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ), 516 hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); 517 break; 518 default: 519 WARN("unhandled status %u\n", req->status_code); 520 } 521 break; 522 } 523 case ERROR_INTERNET_SEC_CERT_ERRORS: 524 case ERROR_INTERNET_SEC_CERT_CN_INVALID: 525 case ERROR_INTERNET_SEC_CERT_DATE_INVALID: 526 case ERROR_INTERNET_INVALID_CA: 527 case ERROR_INTERNET_SEC_CERT_REV_FAILED: 528 if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) { 529 res = ERROR_CANCELLED; 530 break; 531 } 532 if(!req) 533 return ERROR_INVALID_HANDLE; 534 535 536 if( dwFlags & ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) 537 FIXME("%08x contains unsupported flags.\n", dwFlags); 538 539 res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ), 540 hWnd, WININET_InvalidCertificateDialog, (LPARAM) ¶ms ); 541 break; 542 case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: 543 case ERROR_INTERNET_POST_IS_NON_SECURE: 544 FIXME("Need to display dialog for error %d\n", dwError); 545 res = ERROR_SUCCESS; 546 break; 547 default: 548 res = ERROR_NOT_SUPPORTED; 549 } 550 551 if(req) 552 WININET_Release(&req->hdr); 553 return res; 554 } 555 556 /*********************************************************************** 557 * InternetShowSecurityInfoByURLA (@) 558 */ 559 BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window) 560 { 561 FIXME("stub: %s %p\n", url, window); 562 return FALSE; 563 } 564 565 /*********************************************************************** 566 * InternetShowSecurityInfoByURLW (@) 567 */ 568 BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window) 569 { 570 FIXME("stub: %s %p\n", debugstr_w(url), window); 571 return FALSE; 572 } 573 574 /*********************************************************************** 575 * ParseX509EncodedCertificateForListBoxEntry (@) 576 */ 577 DWORD WINAPI ParseX509EncodedCertificateForListBoxEntry(LPBYTE cert, DWORD len, LPSTR szlistbox, LPDWORD listbox) 578 { 579 FIXME("stub: %p %d %s %p\n", cert, len, debugstr_a(szlistbox), listbox); 580 return ERROR_CALL_NOT_IMPLEMENTED; 581 } 582 583 /*********************************************************************** 584 * ShowX509EncodedCertificate (@) 585 */ 586 DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len) 587 { 588 PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING, 589 cert, len); 590 DWORD ret; 591 592 if (certContext) 593 { 594 CRYPTUI_VIEWCERTIFICATE_STRUCTW view; 595 596 memset(&view, 0, sizeof(view)); 597 view.hwndParent = parent; 598 view.pCertContext = certContext; 599 if (CryptUIDlgViewCertificateW(&view, NULL)) 600 ret = ERROR_SUCCESS; 601 else 602 ret = GetLastError(); 603 CertFreeCertificateContext(certContext); 604 } 605 else 606 ret = GetLastError(); 607 return ret; 608 } 609