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