4 * Copyright 2003 Mike McCormack for CodeWeavers Inc.
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.
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.
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
22 #include "wine/port.h"
24 #if defined(__MINGW32__) || defined (_MSC_VER)
36 #include "wine/debug.h"
38 #define NO_SHLWAPI_STREAM
43 #include "wine/unicode.h"
47 #define MAX_STRING_LEN 1024
49 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
51 struct WININET_ErrorDlgParams
60 /***********************************************************************
61 * WININET_GetAuthRealm
63 * Determine the name of the (basic) Authentication realm
65 static BOOL
WININET_GetAuthRealm( HINTERNET hRequest
, LPWSTR szBuf
, DWORD sz
, BOOL proxy
)
69 static const WCHAR szRealm
[] = { 'r','e','a','l','m','=',0 };
72 query
= HTTP_QUERY_PROXY_AUTHENTICATE
;
74 query
= HTTP_QUERY_WWW_AUTHENTICATE
;
76 /* extract the Realm from the response and show it */
78 if( !HttpQueryInfoW( hRequest
, query
, szBuf
, &sz
, &index
) )
82 * FIXME: maybe we should check that we're
83 * dealing with 'Basic' Authentication
85 p
= strchrW( szBuf
, ' ' );
86 if( !p
|| strncmpW( p
+1, szRealm
, strlenW(szRealm
) ) )
88 ERR("response wrong? (%s)\n", debugstr_w(szBuf
));
97 q
= strrchrW( p
, '"' );
106 /* These two are not defined in the public headers */
107 extern DWORD WINAPI
WNetCachePassword(LPSTR
,WORD
,LPSTR
,WORD
,BYTE
,WORD
);
108 extern DWORD WINAPI
WNetGetCachedPassword(LPSTR
,WORD
,LPSTR
,LPWORD
,BYTE
);
110 /***********************************************************************
111 * WININET_GetSetPassword
113 static BOOL
WININET_GetSetPassword( HWND hdlg
, LPCWSTR szServer
,
114 LPCWSTR szRealm
, BOOL bSet
)
116 WCHAR szResource
[0x80], szUserPass
[0x40];
118 HWND hUserItem
, hPassItem
;
119 DWORD r
, dwMagic
= 19;
122 static const WCHAR szColon
[] = { ':',0 };
123 static const WCHAR szbs
[] = { '/', 0 };
125 hUserItem
= GetDlgItem( hdlg
, IDC_USERNAME
);
126 hPassItem
= GetDlgItem( hdlg
, IDC_PASSWORD
);
128 /* now try fetch the username and password */
129 lstrcpyW( szResource
, szServer
);
130 lstrcatW( szResource
, szbs
);
131 lstrcatW( szResource
, szRealm
);
134 * WNetCachePassword is only concerned with the length
135 * of the data stored (which we tell it) and it does
136 * not use strlen() internally so we can add WCHAR data
137 * instead of ASCII data and get it back the same way.
142 GetWindowTextW( hUserItem
, szUserPass
,
143 (sizeof szUserPass
-1)/sizeof(WCHAR
) );
144 lstrcatW(szUserPass
, szColon
);
145 u_len
= strlenW( szUserPass
);
146 GetWindowTextW( hPassItem
, szUserPass
+u_len
,
147 (sizeof szUserPass
)/sizeof(WCHAR
)-u_len
);
149 r_len
= (strlenW( szResource
) + 1)*sizeof(WCHAR
);
150 u_len
= (strlenW( szUserPass
) + 1)*sizeof(WCHAR
);
151 r
= WNetCachePassword( (CHAR
*)szResource
, r_len
,
152 (CHAR
*)szUserPass
, u_len
, dwMagic
, 0 );
154 return ( r
== WN_SUCCESS
);
157 sz
= sizeof szUserPass
;
158 r_len
= (strlenW( szResource
) + 1)*sizeof(WCHAR
);
159 r
= WNetGetCachedPassword( (CHAR
*)szResource
, r_len
,
160 (CHAR
*)szUserPass
, &sz
, dwMagic
);
161 if( r
!= WN_SUCCESS
)
164 p
= strchrW( szUserPass
, ':' );
168 SetWindowTextW( hUserItem
, szUserPass
);
169 SetWindowTextW( hPassItem
, p
+1 );
175 /***********************************************************************
176 * WININET_SetAuthorization
178 static BOOL
WININET_SetAuthorization( HINTERNET hRequest
, LPWSTR username
,
179 LPWSTR password
, BOOL proxy
)
181 http_request_t
*request
;
182 http_session_t
*session
;
186 request
= (http_request_t
*) get_handle_object( hRequest
);
190 session
= request
->session
;
191 if (NULL
== session
|| session
->hdr
.htype
!= WH_HHTTPSESSION
)
193 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
197 p
= heap_strdupW(username
);
201 q
= heap_strdupW(password
);
210 appinfo_t
*hIC
= session
->appInfo
;
212 heap_free(hIC
->proxyUsername
);
213 hIC
->proxyUsername
= p
;
215 heap_free(hIC
->proxyPassword
);
216 hIC
->proxyPassword
= q
;
220 heap_free(session
->userName
);
221 session
->userName
= p
;
223 heap_free(session
->password
);
224 session
->password
= q
;
230 WININET_Release( &request
->hdr
);
234 /***********************************************************************
235 * WININET_ProxyPasswordDialog
237 static INT_PTR WINAPI
WININET_ProxyPasswordDialog(
238 HWND hdlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
241 struct WININET_ErrorDlgParams
*params
;
242 WCHAR szRealm
[0x80], szServer
[0x80];
244 if( uMsg
== WM_INITDIALOG
)
246 TRACE("WM_INITDIALOG (%08lx)\n", lParam
);
248 /* save the parameter list */
249 params
= (struct WININET_ErrorDlgParams
*) lParam
;
250 SetWindowLongPtrW( hdlg
, GWLP_USERDATA
, lParam
);
252 /* extract the Realm from the proxy response and show it */
253 if( WININET_GetAuthRealm( params
->req
->hdr
.hInternet
,
254 szRealm
, sizeof szRealm
/sizeof(WCHAR
), TRUE
) )
256 hitem
= GetDlgItem( hdlg
, IDC_REALM
);
257 SetWindowTextW( hitem
, szRealm
);
260 hitem
= GetDlgItem( hdlg
, IDC_PROXY
);
261 SetWindowTextW( hitem
, params
->req
->session
->appInfo
->proxy
);
263 WININET_GetSetPassword( hdlg
, szServer
, szRealm
, FALSE
);
268 params
= (struct WININET_ErrorDlgParams
*)
269 GetWindowLongPtrW( hdlg
, GWLP_USERDATA
);
276 WCHAR username
[0x20], password
[0x20];
279 hitem
= GetDlgItem( hdlg
, IDC_USERNAME
);
281 GetWindowTextW( hitem
, username
, sizeof username
/sizeof(WCHAR
) );
284 hitem
= GetDlgItem( hdlg
, IDC_PASSWORD
);
286 GetWindowTextW( hitem
, password
, sizeof password
/sizeof(WCHAR
) );
288 hitem
= GetDlgItem( hdlg
, IDC_SAVEPASSWORD
);
290 SendMessageW( hitem
, BM_GETSTATE
, 0, 0 ) &&
291 WININET_GetAuthRealm( params
->req
->hdr
.hInternet
,
292 szRealm
, sizeof szRealm
/sizeof(WCHAR
), TRUE
) )
293 WININET_GetSetPassword( hdlg
, params
->req
->session
->appInfo
->proxy
, szRealm
, TRUE
);
294 WININET_SetAuthorization( params
->req
->hdr
.hInternet
, username
, password
, TRUE
);
296 EndDialog( hdlg
, ERROR_INTERNET_FORCE_RETRY
);
299 if( wParam
== IDCANCEL
)
301 EndDialog( hdlg
, 0 );
309 /***********************************************************************
310 * WININET_PasswordDialog
312 static INT_PTR WINAPI
WININET_PasswordDialog(
313 HWND hdlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
316 struct WININET_ErrorDlgParams
*params
;
317 WCHAR szRealm
[0x80], szServer
[0x80];
319 if( uMsg
== WM_INITDIALOG
)
321 TRACE("WM_INITDIALOG (%08lx)\n", lParam
);
323 /* save the parameter list */
324 params
= (struct WININET_ErrorDlgParams
*) lParam
;
325 SetWindowLongPtrW( hdlg
, GWLP_USERDATA
, lParam
);
327 /* extract the Realm from the response and show it */
328 if( WININET_GetAuthRealm( params
->req
->hdr
.hInternet
,
329 szRealm
, sizeof szRealm
/sizeof(WCHAR
), FALSE
) )
331 hitem
= GetDlgItem( hdlg
, IDC_REALM
);
332 SetWindowTextW( hitem
, szRealm
);
335 hitem
= GetDlgItem( hdlg
, IDC_SERVER
);
336 SetWindowTextW( hitem
, params
->req
->session
->hostName
);
338 WININET_GetSetPassword( hdlg
, szServer
, szRealm
, FALSE
);
343 params
= (struct WININET_ErrorDlgParams
*)
344 GetWindowLongPtrW( hdlg
, GWLP_USERDATA
);
351 WCHAR username
[0x20], password
[0x20];
354 hitem
= GetDlgItem( hdlg
, IDC_USERNAME
);
356 GetWindowTextW( hitem
, username
, sizeof username
/sizeof(WCHAR
) );
359 hitem
= GetDlgItem( hdlg
, IDC_PASSWORD
);
361 GetWindowTextW( hitem
, password
, sizeof password
/sizeof(WCHAR
) );
363 hitem
= GetDlgItem( hdlg
, IDC_SAVEPASSWORD
);
365 SendMessageW( hitem
, BM_GETSTATE
, 0, 0 ) &&
366 WININET_GetAuthRealm( params
->req
->hdr
.hInternet
,
367 szRealm
, sizeof szRealm
/sizeof(WCHAR
), FALSE
))
369 WININET_GetSetPassword( hdlg
, params
->req
->session
->hostName
, szRealm
, TRUE
);
371 WININET_SetAuthorization( params
->req
->hdr
.hInternet
, username
, password
, FALSE
);
373 EndDialog( hdlg
, ERROR_INTERNET_FORCE_RETRY
);
376 if( wParam
== IDCANCEL
)
378 EndDialog( hdlg
, 0 );
386 /***********************************************************************
387 * WININET_InvalidCertificateDialog
389 static INT_PTR WINAPI
WININET_InvalidCertificateDialog(
390 HWND hdlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
392 struct WININET_ErrorDlgParams
*params
;
396 if( uMsg
== WM_INITDIALOG
)
398 TRACE("WM_INITDIALOG (%08lx)\n", lParam
);
400 /* save the parameter list */
401 params
= (struct WININET_ErrorDlgParams
*) lParam
;
402 SetWindowLongPtrW( hdlg
, GWLP_USERDATA
, lParam
);
404 switch( params
->dwError
)
406 case ERROR_INTERNET_INVALID_CA
:
407 LoadStringW( WININET_hModule
, IDS_CERT_CA_INVALID
, buf
, 1024 );
409 case ERROR_INTERNET_SEC_CERT_DATE_INVALID
:
410 LoadStringW( WININET_hModule
, IDS_CERT_DATE_INVALID
, buf
, 1024 );
412 case ERROR_INTERNET_SEC_CERT_CN_INVALID
:
413 LoadStringW( WININET_hModule
, IDS_CERT_CN_INVALID
, buf
, 1024 );
415 case ERROR_INTERNET_SEC_CERT_ERRORS
:
416 /* FIXME: We should fetch information about the
417 * certificate here and show all the relevant errors.
419 LoadStringW( WININET_hModule
, IDS_CERT_ERRORS
, buf
, 1024 );
422 FIXME( "No message for error %d\n", params
->dwError
);
426 hitem
= GetDlgItem( hdlg
, IDC_CERT_ERROR
);
427 SetWindowTextW( hitem
, buf
);
432 params
= (struct WININET_ErrorDlgParams
*)
433 GetWindowLongPtrW( hdlg
, GWLP_USERDATA
);
442 if( params
->dwFlags
& FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS
)
444 http_request_t
*req
= params
->req
;
445 DWORD flags
, size
= sizeof(flags
);
447 InternetQueryOptionW( req
->hdr
.hInternet
, INTERNET_OPTION_SECURITY_FLAGS
, &flags
, &size
);
448 switch( params
->dwError
)
450 case ERROR_INTERNET_INVALID_CA
:
451 flags
|= SECURITY_FLAG_IGNORE_UNKNOWN_CA
;
453 case ERROR_INTERNET_SEC_CERT_DATE_INVALID
:
454 flags
|= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;
456 case ERROR_INTERNET_SEC_CERT_CN_INVALID
:
457 flags
|= SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;
459 case ERROR_INTERNET_SEC_CERT_REV_FAILED
:
460 flags
|= SECURITY_FLAG_IGNORE_REVOCATION
;
462 case ERROR_INTERNET_SEC_CERT_ERRORS
:
463 if(flags
& _SECURITY_FLAG_CERT_REV_FAILED
)
464 flags
|= SECURITY_FLAG_IGNORE_REVOCATION
;
465 if(flags
& _SECURITY_FLAG_CERT_INVALID_CA
)
466 flags
|= SECURITY_FLAG_IGNORE_UNKNOWN_CA
;
467 if(flags
& _SECURITY_FLAG_CERT_INVALID_CN
)
468 flags
|= SECURITY_FLAG_IGNORE_CERT_CN_INVALID
;
469 if(flags
& _SECURITY_FLAG_CERT_INVALID_DATE
)
470 flags
|= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;
473 /* FIXME: Use helper function */
474 flags
|= SECURITY_FLAG_SECURE
;
475 req
->security_flags
|= flags
;
477 req
->netconn
->security_flags
|= flags
;
480 EndDialog( hdlg
, res
? ERROR_SUCCESS
: ERROR_NOT_SUPPORTED
);
483 if( wParam
== IDCANCEL
)
485 TRACE("Pressed cancel.\n");
487 EndDialog( hdlg
, ERROR_CANCELLED
);
496 /***********************************************************************
497 * WININET_GetConnectionStatus
499 static INT
WININET_GetConnectionStatus( HINTERNET hRequest
)
501 WCHAR szStatus
[0x20];
502 DWORD sz
, index
, dwStatus
;
504 TRACE("%p\n", hRequest
);
506 sz
= sizeof szStatus
;
508 if( !HttpQueryInfoW( hRequest
, HTTP_QUERY_STATUS_CODE
,
509 szStatus
, &sz
, &index
))
511 dwStatus
= atoiW( szStatus
);
513 TRACE("request %p status = %d\n", hRequest
, dwStatus
);
518 /***********************************************************************
521 DWORD WINAPI
InternetErrorDlg(HWND hWnd
, HINTERNET hRequest
,
522 DWORD dwError
, DWORD dwFlags
, LPVOID
* lppvData
)
524 struct WININET_ErrorDlgParams params
;
525 http_request_t
*req
= NULL
;
526 DWORD res
= ERROR_SUCCESS
;
528 TRACE("%p %p %d %08x %p\n", hWnd
, hRequest
, dwError
, dwFlags
, lppvData
);
530 if( !hWnd
&& !(dwFlags
& FLAGS_ERROR_UI_FLAGS_NO_UI
) )
531 return ERROR_INVALID_HANDLE
;
534 req
= (http_request_t
*)get_handle_object(hRequest
);
536 return ERROR_INVALID_HANDLE
;
537 if(req
->hdr
.htype
!= WH_HHTTPREQ
)
538 return ERROR_SUCCESS
; /* Yes, that was tested */
543 params
.dwError
= dwError
;
544 params
.dwFlags
= dwFlags
;
545 params
.lppvData
= lppvData
;
550 case ERROR_INTERNET_INCORRECT_PASSWORD
: {
553 if( !dwError
&& !(dwFlags
& FLAGS_ERROR_UI_FILTER_FOR_ERRORS
) )
556 return ERROR_INVALID_HANDLE
;
558 dwStatus
= WININET_GetConnectionStatus( hRequest
);
561 case HTTP_STATUS_PROXY_AUTH_REQ
:
562 res
= DialogBoxParamW( WININET_hModule
, MAKEINTRESOURCEW( IDD_PROXYDLG
),
563 hWnd
, WININET_ProxyPasswordDialog
, (LPARAM
) ¶ms
);
565 case HTTP_STATUS_DENIED
:
566 res
= DialogBoxParamW( WININET_hModule
, MAKEINTRESOURCEW( IDD_AUTHDLG
),
567 hWnd
, WININET_PasswordDialog
, (LPARAM
) ¶ms
);
570 WARN("unhandled status %u\n", dwStatus
);
574 case ERROR_INTERNET_SEC_CERT_ERRORS
:
575 case ERROR_INTERNET_SEC_CERT_CN_INVALID
:
576 case ERROR_INTERNET_SEC_CERT_DATE_INVALID
:
577 case ERROR_INTERNET_INVALID_CA
:
578 case ERROR_INTERNET_SEC_CERT_REV_FAILED
:
579 if( dwFlags
& FLAGS_ERROR_UI_FLAGS_NO_UI
) {
580 res
= ERROR_CANCELLED
;
584 return ERROR_INVALID_HANDLE
;
587 if( dwFlags
& ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS
)
588 FIXME("%08x contains unsupported flags.\n", dwFlags
);
590 res
= DialogBoxParamW( WININET_hModule
, MAKEINTRESOURCEW( IDD_INVCERTDLG
),
591 hWnd
, WININET_InvalidCertificateDialog
, (LPARAM
) ¶ms
);
593 case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR
:
594 case ERROR_INTERNET_POST_IS_NON_SECURE
:
595 FIXME("Need to display dialog for error %d\n", dwError
);
599 res
= ERROR_NOT_SUPPORTED
;
603 WININET_Release(&req
->hdr
);