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, 139 (sizeof szUserPass-1)/sizeof(WCHAR) ); 140 lstrcatW(szUserPass, szColon); 141 u_len = strlenW( szUserPass ); 142 GetWindowTextW( hPassItem, szUserPass+u_len, 143 (sizeof szUserPass)/sizeof(WCHAR)-u_len ); 144 145 r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR); 146 u_len = (strlenW( szUserPass ) + 1)*sizeof(WCHAR); 147 r = WNetCachePassword( (CHAR*)szResource, r_len, 148 (CHAR*)szUserPass, u_len, dwMagic, 0 ); 149 150 return ( r == WN_SUCCESS ); 151 } 152 153 sz = sizeof szUserPass; 154 r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR); 155 r = WNetGetCachedPassword( (CHAR*)szResource, r_len, 156 (CHAR*)szUserPass, &sz, dwMagic ); 157 if( r != WN_SUCCESS ) 158 return FALSE; 159 160 p = strchrW( szUserPass, ':' ); 161 if( p ) 162 { 163 *p = 0; 164 SetWindowTextW( hUserItem, szUserPass ); 165 SetWindowTextW( hPassItem, p+1 ); 166 } 167 168 return TRUE; 169 } 170 171 /*********************************************************************** 172 * WININET_SetAuthorization 173 */ 174 static BOOL WININET_SetAuthorization( http_request_t *request, LPWSTR username, 175 LPWSTR password, BOOL proxy ) 176 { 177 http_session_t *session = request->session; 178 LPWSTR p, q; 179 180 p = heap_strdupW(username); 181 if( !p ) 182 return FALSE; 183 184 q = heap_strdupW(password); 185 if( !q ) 186 { 187 heap_free(p); 188 return FALSE; 189 } 190 191 if (proxy) 192 { 193 appinfo_t *hIC = session->appInfo; 194 195 heap_free(hIC->proxyUsername); 196 hIC->proxyUsername = p; 197 198 heap_free(hIC->proxyPassword); 199 hIC->proxyPassword = q; 200 } 201 else 202 { 203 heap_free(session->userName); 204 session->userName = p; 205 206 heap_free(session->password); 207 session->password = q; 208 } 209 210 return TRUE; 211 } 212 213 /*********************************************************************** 214 * WININET_ProxyPasswordDialog 215 */ 216 static INT_PTR WINAPI WININET_ProxyPasswordDialog( 217 HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 218 { 219 HWND hitem; 220 struct WININET_ErrorDlgParams *params; 221 WCHAR szRealm[0x80], szServer[0x80]; 222 223 if( uMsg == WM_INITDIALOG ) 224 { 225 TRACE("WM_INITDIALOG (%08lx)\n", lParam); 226 227 /* save the parameter list */ 228 params = (struct WININET_ErrorDlgParams*) lParam; 229 SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); 230 231 /* extract the Realm from the proxy response and show it */ 232 if( WININET_GetAuthRealm( params->req->hdr.hInternet, 233 szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) ) 234 { 235 hitem = GetDlgItem( hdlg, IDC_REALM ); 236 SetWindowTextW( hitem, szRealm ); 237 } 238 239 hitem = GetDlgItem( hdlg, IDC_PROXY ); 240 SetWindowTextW( hitem, params->req->session->appInfo->proxy ); 241 242 WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); 243 244 return TRUE; 245 } 246 247 params = (struct WININET_ErrorDlgParams*) 248 GetWindowLongPtrW( hdlg, GWLP_USERDATA ); 249 250 switch( uMsg ) 251 { 252 case WM_COMMAND: 253 if( wParam == IDOK ) 254 { 255 WCHAR username[0x20], password[0x20]; 256 257 username[0] = 0; 258 hitem = GetDlgItem( hdlg, IDC_USERNAME ); 259 if( hitem ) 260 GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); 261 262 password[0] = 0; 263 hitem = GetDlgItem( hdlg, IDC_PASSWORD ); 264 if( hitem ) 265 GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); 266 267 hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); 268 if( hitem && 269 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && 270 WININET_GetAuthRealm( params->req->hdr.hInternet, 271 szRealm, sizeof szRealm/sizeof(WCHAR), TRUE) ) 272 WININET_GetSetPassword( hdlg, params->req->session->appInfo->proxy, szRealm, TRUE ); 273 WININET_SetAuthorization( params->req, username, password, TRUE ); 274 275 EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); 276 return TRUE; 277 } 278 if( wParam == IDCANCEL ) 279 { 280 EndDialog( hdlg, 0 ); 281 return TRUE; 282 } 283 break; 284 } 285 return FALSE; 286 } 287 288 /*********************************************************************** 289 * WININET_PasswordDialog 290 */ 291 static INT_PTR WINAPI WININET_PasswordDialog( 292 HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 293 { 294 HWND hitem; 295 struct WININET_ErrorDlgParams *params; 296 WCHAR szRealm[0x80], szServer[0x80]; 297 298 if( uMsg == WM_INITDIALOG ) 299 { 300 TRACE("WM_INITDIALOG (%08lx)\n", lParam); 301 302 /* save the parameter list */ 303 params = (struct WININET_ErrorDlgParams*) lParam; 304 SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); 305 306 /* extract the Realm from the response and show it */ 307 if( WININET_GetAuthRealm( params->req->hdr.hInternet, 308 szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) ) 309 { 310 hitem = GetDlgItem( hdlg, IDC_REALM ); 311 SetWindowTextW( hitem, szRealm ); 312 } 313 314 hitem = GetDlgItem( hdlg, IDC_SERVER ); 315 SetWindowTextW( hitem, params->req->session->hostName ); 316 317 WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); 318 319 return TRUE; 320 } 321 322 params = (struct WININET_ErrorDlgParams*) 323 GetWindowLongPtrW( hdlg, GWLP_USERDATA ); 324 325 switch( uMsg ) 326 { 327 case WM_COMMAND: 328 if( wParam == IDOK ) 329 { 330 WCHAR username[0x20], password[0x20]; 331 332 username[0] = 0; 333 hitem = GetDlgItem( hdlg, IDC_USERNAME ); 334 if( hitem ) 335 GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); 336 337 password[0] = 0; 338 hitem = GetDlgItem( hdlg, IDC_PASSWORD ); 339 if( hitem ) 340 GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); 341 342 hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); 343 if( hitem && 344 SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && 345 WININET_GetAuthRealm( params->req->hdr.hInternet, 346 szRealm, sizeof szRealm/sizeof(WCHAR), FALSE )) 347 { 348 WININET_GetSetPassword( hdlg, params->req->session->hostName, szRealm, TRUE ); 349 } 350 WININET_SetAuthorization( params->req, username, password, FALSE ); 351 352 EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); 353 return TRUE; 354 } 355 if( wParam == IDCANCEL ) 356 { 357 EndDialog( hdlg, 0 ); 358 return TRUE; 359 } 360 break; 361 } 362 return FALSE; 363 } 364 365 /*********************************************************************** 366 * WININET_InvalidCertificateDialog 367 */ 368 static INT_PTR WINAPI WININET_InvalidCertificateDialog( 369 HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 370 { 371 struct WININET_ErrorDlgParams *params; 372 HWND hitem; 373 WCHAR buf[1024]; 374 375 if( uMsg == WM_INITDIALOG ) 376 { 377 TRACE("WM_INITDIALOG (%08lx)\n", lParam); 378 379 /* save the parameter list */ 380 params = (struct WININET_ErrorDlgParams*) lParam; 381 SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); 382 383 switch( params->dwError ) 384 { 385 case ERROR_INTERNET_INVALID_CA: 386 LoadStringW( WININET_hModule, IDS_CERT_CA_INVALID, buf, 1024 ); 387 break; 388 case ERROR_INTERNET_SEC_CERT_DATE_INVALID: 389 LoadStringW( WININET_hModule, IDS_CERT_DATE_INVALID, buf, 1024 ); 390 break; 391 case ERROR_INTERNET_SEC_CERT_CN_INVALID: 392 LoadStringW( WININET_hModule, IDS_CERT_CN_INVALID, buf, 1024 ); 393 break; 394 case ERROR_INTERNET_SEC_CERT_ERRORS: 395 /* FIXME: We should fetch information about the 396 * certificate here and show all the relevant errors. 397 */ 398 LoadStringW( WININET_hModule, IDS_CERT_ERRORS, buf, 1024 ); 399 break; 400 default: 401 FIXME( "No message for error %d\n", params->dwError ); 402 buf[0] = '\0'; 403 } 404 405 hitem = GetDlgItem( hdlg, IDC_CERT_ERROR ); 406 SetWindowTextW( hitem, buf ); 407 408 return TRUE; 409 } 410 411 params = (struct WININET_ErrorDlgParams*) 412 GetWindowLongPtrW( hdlg, GWLP_USERDATA ); 413 414 switch( uMsg ) 415 { 416 case WM_COMMAND: 417 if( wParam == IDOK ) 418 { 419 if( params->dwFlags & FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) 420 { 421 http_request_t *req = params->req; 422 DWORD flags, size = sizeof(flags); 423 424 InternetQueryOptionW( req->hdr.hInternet, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size ); 425 switch( params->dwError ) 426 { 427 case ERROR_INTERNET_INVALID_CA: 428 flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; 429 break; 430 case ERROR_INTERNET_SEC_CERT_DATE_INVALID: 431 flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 432 break; 433 case ERROR_INTERNET_SEC_CERT_CN_INVALID: 434 flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; 435 break; 436 case ERROR_INTERNET_SEC_CERT_REV_FAILED: 437 flags |= SECURITY_FLAG_IGNORE_REVOCATION; 438 break; 439 case ERROR_INTERNET_SEC_CERT_ERRORS: 440 if(flags & _SECURITY_FLAG_CERT_REV_FAILED) 441 flags |= SECURITY_FLAG_IGNORE_REVOCATION; 442 if(flags & _SECURITY_FLAG_CERT_INVALID_CA) 443 flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; 444 if(flags & _SECURITY_FLAG_CERT_INVALID_CN) 445 flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; 446 if(flags & _SECURITY_FLAG_CERT_INVALID_DATE) 447 flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 448 break; 449 } 450 /* FIXME: Use helper function */ 451 flags |= SECURITY_FLAG_SECURE; 452 req->security_flags |= flags; 453 if(is_valid_netconn(req->netconn)) 454 req->netconn->security_flags |= flags; 455 } 456 457 EndDialog( hdlg, ERROR_SUCCESS ); 458 return TRUE; 459 } 460 if( wParam == IDCANCEL ) 461 { 462 TRACE("Pressed cancel.\n"); 463 464 EndDialog( hdlg, ERROR_CANCELLED ); 465 return TRUE; 466 } 467 break; 468 } 469 470 return FALSE; 471 } 472 473 /*********************************************************************** 474 * InternetErrorDlg 475 */ 476 DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, 477 DWORD dwError, DWORD dwFlags, LPVOID* lppvData) 478 { 479 struct WININET_ErrorDlgParams params; 480 http_request_t *req = NULL; 481 DWORD res = ERROR_SUCCESS; 482 483 TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData); 484 485 if( !hWnd && !(dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI) ) 486 return ERROR_INVALID_HANDLE; 487 488 if(hRequest) { 489 req = (http_request_t*)get_handle_object(hRequest); 490 if(!req) 491 return ERROR_INVALID_HANDLE; 492 if(req->hdr.htype != WH_HHTTPREQ) 493 return ERROR_SUCCESS; /* Yes, that was tested */ 494 } 495 496 params.req = req; 497 params.hWnd = hWnd; 498 params.dwError = dwError; 499 params.dwFlags = dwFlags; 500 params.lppvData = lppvData; 501 502 switch( dwError ) 503 { 504 case ERROR_SUCCESS: 505 case ERROR_INTERNET_INCORRECT_PASSWORD: { 506 if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) 507 break; 508 if(!req) 509 return ERROR_INVALID_HANDLE; 510 511 switch(req->status_code) { 512 case HTTP_STATUS_PROXY_AUTH_REQ: 513 res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ), 514 hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); 515 break; 516 case HTTP_STATUS_DENIED: 517 res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ), 518 hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); 519 break; 520 default: 521 WARN("unhandled status %u\n", req->status_code); 522 } 523 break; 524 } 525 case ERROR_INTERNET_SEC_CERT_ERRORS: 526 case ERROR_INTERNET_SEC_CERT_CN_INVALID: 527 case ERROR_INTERNET_SEC_CERT_DATE_INVALID: 528 case ERROR_INTERNET_INVALID_CA: 529 case ERROR_INTERNET_SEC_CERT_REV_FAILED: 530 if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) { 531 res = ERROR_CANCELLED; 532 break; 533 } 534 if(!req) 535 return ERROR_INVALID_HANDLE; 536 537 538 if( dwFlags & ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS ) 539 FIXME("%08x contains unsupported flags.\n", dwFlags); 540 541 res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ), 542 hWnd, WININET_InvalidCertificateDialog, (LPARAM) ¶ms ); 543 break; 544 case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: 545 case ERROR_INTERNET_POST_IS_NON_SECURE: 546 FIXME("Need to display dialog for error %d\n", dwError); 547 res = ERROR_SUCCESS; 548 break; 549 default: 550 res = ERROR_NOT_SUPPORTED; 551 } 552 553 if(req) 554 WININET_Release(&req->hdr); 555 return res; 556 } 557 558 /*********************************************************************** 559 * InternetShowSecurityInfoByURLA (@) 560 */ 561 BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window) 562 { 563 FIXME("stub: %s %p\n", url, window); 564 return FALSE; 565 } 566 567 /*********************************************************************** 568 * InternetShowSecurityInfoByURLW (@) 569 */ 570 BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window) 571 { 572 FIXME("stub: %s %p\n", debugstr_w(url), window); 573 return FALSE; 574 } 575 576 /*********************************************************************** 577 * ParseX509EncodedCertificateForListBoxEntry (@) 578 */ 579 DWORD WINAPI ParseX509EncodedCertificateForListBoxEntry(LPBYTE cert, DWORD len, LPSTR szlistbox, LPDWORD listbox) 580 { 581 FIXME("stub: %p %d %s %p\n", cert, len, debugstr_a(szlistbox), listbox); 582 return ERROR_CALL_NOT_IMPLEMENTED; 583 } 584 585 /*********************************************************************** 586 * ShowX509EncodedCertificate (@) 587 */ 588 DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len) 589 { 590 PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING, 591 cert, len); 592 DWORD ret; 593 594 if (certContext) 595 { 596 CRYPTUI_VIEWCERTIFICATE_STRUCTW view; 597 598 memset(&view, 0, sizeof(view)); 599 view.hwndParent = parent; 600 view.pCertContext = certContext; 601 if (CryptUIDlgViewCertificateW(&view, NULL)) 602 ret = ERROR_SUCCESS; 603 else 604 ret = GetLastError(); 605 CertFreeCertificateContext(certContext); 606 } 607 else 608 ret = GetLastError(); 609 return ret; 610 } 611