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