Fixed bitmap range checking to avoid integer overflows.
[wine] / dlls / wininet / dialogs.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.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 "winnls.h"
32 #include "wine/debug.h"
33 #include "winerror.h"
34 #define NO_SHLWAPI_STREAM
35 #include "shlwapi.h"
36
37 #include "internet.h"
38
39 #include "wine/unicode.h"
40
41 #include "resource.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
44
45 struct WININET_ErrorDlgParams
46 {
47     HWND       hWnd;
48     HINTERNET  hRequest;
49     DWORD      dwError;
50     DWORD      dwFlags;
51     LPVOID*    lppvData;
52 };
53
54 /***********************************************************************
55  *         WININET_GetProxyServer
56  *
57  *  Determine the name of the proxy server the request is using
58  */
59 static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPSTR szBuf, DWORD sz )
60 {
61     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hRequest;
62     LPWININETHTTPSESSIONA lpwhs = NULL;
63     LPWININETAPPINFOA hIC = NULL;
64     LPSTR p;
65
66     if (NULL == lpwhr)
67         return FALSE;
68
69     lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
70     if (NULL == lpwhs)
71         return FALSE;
72
73     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
74     if (NULL == hIC)
75         return FALSE;
76
77     strncpy(szBuf, hIC->lpszProxy, sz);
78
79     /* FIXME: perhaps it would be better to use InternetCrackUrl here */
80     p = strchr(szBuf, ':');
81     if(*p)
82         *p = 0;
83
84     return TRUE;
85 }
86
87 /***********************************************************************
88  *         WININET_GetAuthRealm
89  *
90  *  Determine the name of the (basic) Authentication realm
91  */
92 static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPSTR szBuf, DWORD sz )
93 {
94     LPSTR p, q;
95     DWORD index;
96
97     /* extract the Realm from the proxy response and show it */
98     index = 0;
99     if( !HttpQueryInfoA( hRequest, HTTP_QUERY_PROXY_AUTHENTICATE,
100                          szBuf, &sz, &index) )
101         return FALSE;
102
103     /*
104      * FIXME: maybe we should check that we're
105      * dealing with 'Basic' Authentication
106      */
107     p = strchr( szBuf, ' ' );
108     if( p && !strncmp( p+1, "realm=", 6 ) )
109     {
110         /* remove quotes */
111         p += 7;
112         if( *p == '"' )
113         {
114             p++;
115             q = strrchr( p, '"' );
116             if( q )
117                 *q = 0;
118         }
119     }
120
121     strcpy( szBuf, p );
122
123     return TRUE;
124 }
125
126 /***********************************************************************
127  *         WININET_GetSetPassword
128  */
129 static BOOL WININET_GetSetPassword( HWND hdlg, LPCSTR szServer, 
130                                     LPCSTR szRealm, BOOL bSet )
131 {
132     CHAR szResource[0x80], szUserPass[0x40];
133     LPSTR p;
134     HWND hUserItem, hPassItem;
135     DWORD r, dwMagic = 19;
136     UINT len;
137     WORD sz;
138
139     hUserItem = GetDlgItem( hdlg, IDC_USERNAME );
140     hPassItem = GetDlgItem( hdlg, IDC_PASSWORD );
141
142     /* now try fetch the username and password */
143     strcpy( szResource, szServer);
144     strcat( szResource, "/");
145     strcat( szResource, szRealm);
146
147     if( bSet )
148     {
149         szUserPass[0] = 0;
150         GetWindowTextA( hUserItem, szUserPass, sizeof szUserPass-1 );
151         strcat(szUserPass, ":");
152         len = strlen( szUserPass );
153         GetWindowTextA( hPassItem, szUserPass+len, sizeof szUserPass-len );
154
155         r = WNetCachePassword( szResource, strlen( szResource ) + 1,
156                             szUserPass, strlen( szUserPass ) + 1, dwMagic, 0 );
157
158         return ( r == WN_SUCCESS );
159     }
160
161     sz = sizeof szUserPass;
162     r = WNetGetCachedPassword( szResource, strlen( szResource ) + 1,
163                                szUserPass, &sz, dwMagic );
164     if( r != WN_SUCCESS )
165         return FALSE;
166
167     p = strchr( szUserPass, ':' );
168     if( p )
169     {
170         *p = 0;
171         SetWindowTextA( hUserItem, szUserPass );
172         SetWindowTextA( hPassItem, p+1 );
173     }
174
175     return TRUE;
176 }
177
178 /***********************************************************************
179  *         WININET_SetProxyAuthorization
180  */
181 static BOOL WININET_SetProxyAuthorization( HINTERNET hRequest,
182                                          LPSTR username, LPSTR password )
183 {
184     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hRequest;
185     LPWININETHTTPSESSIONA lpwhs;
186     LPWININETAPPINFOA hIC;
187     LPSTR p;
188
189     lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
190     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
191     {
192         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
193         return FALSE;
194     }
195
196     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
197
198     p = HeapAlloc( GetProcessHeap(), 0, strlen( username ) + 1 );
199     if( !p )
200         return FALSE;
201     
202     strcpy( p, username );
203     hIC->lpszProxyUsername = p;
204
205     p = HeapAlloc( GetProcessHeap(), 0, strlen( password ) + 1 );
206     if( !p )
207         return FALSE;
208     
209     strcpy( p, password );
210     hIC->lpszProxyPassword = p;
211
212     return TRUE;
213 }
214
215 /***********************************************************************
216  *         WININET_ProxyPasswordDialog
217  */
218 static INT_PTR WINAPI WININET_ProxyPasswordDialog(
219     HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
220 {
221     HWND hitem;
222     struct WININET_ErrorDlgParams *params;
223     CHAR szRealm[0x80], szServer[0x80];
224
225     if( uMsg == WM_INITDIALOG )
226     {
227         TRACE("WM_INITDIALOG (%08lx)\n", lParam);
228
229         /* save the parameter list */
230         params = (struct WININET_ErrorDlgParams*) lParam;
231         SetWindowLongW( hdlg, GWL_USERDATA, lParam );
232
233         /* extract the Realm from the proxy response and show it */
234         if( WININET_GetAuthRealm( params->hRequest,
235                                   szRealm, sizeof szRealm) )
236         {
237             hitem = GetDlgItem( hdlg, IDC_REALM );
238             SetWindowTextA( hitem, szRealm );
239         }
240
241         /* extract the name of the proxy server */
242         if( WININET_GetProxyServer( params->hRequest, 
243                                     szServer, sizeof szServer) )
244         {
245             hitem = GetDlgItem( hdlg, IDC_PROXY );
246             SetWindowTextA( hitem, szServer );
247         }
248
249         WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE );
250
251         return TRUE;
252     }
253
254     params = (struct WININET_ErrorDlgParams*)
255                  GetWindowLongW( hdlg, GWL_USERDATA );
256
257     switch( uMsg )
258     {
259     case WM_COMMAND:
260         if( wParam == IDOK )
261         {
262             LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) params->hRequest;
263             CHAR username[0x20], password[0x20];
264
265             username[0] = 0;
266             hitem = GetDlgItem( hdlg, IDC_USERNAME );
267             if( hitem )
268                 GetWindowTextA( hitem, username, sizeof username );
269             
270             password[0] = 0;
271             hitem = GetDlgItem( hdlg, IDC_PASSWORD );
272             if( hitem )
273                 GetWindowTextA( hitem, password, sizeof password );
274
275             hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD );
276             if( hitem &&
277                 SendMessageA( hitem, BM_GETSTATE, 0, 0 ) &&
278                 WININET_GetAuthRealm( params->hRequest,
279                                   szRealm, sizeof szRealm) &&
280                 WININET_GetProxyServer( params->hRequest, 
281                                     szServer, sizeof szServer) )
282             {
283                 WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE );
284             }
285             WININET_SetProxyAuthorization( lpwhr, username, password );
286
287             EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY );
288             return TRUE;
289         }
290         if( wParam == IDCANCEL )
291         {
292             EndDialog( hdlg, 0 );
293             return TRUE;
294         }
295         break;
296     }
297     return FALSE;
298 }
299
300 /***********************************************************************
301  *         WININET_GetConnectionStatus
302  */
303 static INT WININET_GetConnectionStatus( HINTERNET hRequest )
304 {
305     CHAR szStatus[0x20];
306     DWORD sz, index, dwStatus;
307
308     TRACE("%p\n", hRequest );
309
310     sz = sizeof szStatus;
311     index = 0;
312     if( !HttpQueryInfoA( hRequest, HTTP_QUERY_STATUS_CODE,
313                     szStatus, &sz, &index))
314         return -1;
315     dwStatus = atoi( szStatus );
316
317     TRACE("request %p status = %ld\n", hRequest, dwStatus );
318
319     return dwStatus;
320 }
321
322
323 /***********************************************************************
324  *         InternetErrorDlg
325  */
326 DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest,
327                  DWORD dwError, DWORD dwFlags, LPVOID* lppvData)
328 {
329     struct WININET_ErrorDlgParams params;
330     HMODULE hwininet = GetModuleHandleA( "wininet.dll" );
331     INT dwStatus;
332
333     TRACE("%p %p %ld %08lx %p\n", hWnd, hRequest, dwError, dwFlags, lppvData);
334
335     params.hWnd = hWnd;
336     params.hRequest = hRequest;
337     params.dwError = dwError;
338     params.dwFlags = dwFlags;
339     params.lppvData = lppvData;
340
341     switch( dwError )
342     {
343     case ERROR_SUCCESS:
344         if( !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) )
345             return 0;
346         dwStatus = WININET_GetConnectionStatus( hRequest );
347         if( HTTP_STATUS_PROXY_AUTH_REQ != dwStatus )
348             return ERROR_SUCCESS;
349         return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ),
350                     hWnd, WININET_ProxyPasswordDialog, (LPARAM) &params );
351
352     case ERROR_INTERNET_INCORRECT_PASSWORD:
353         return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ),
354                     hWnd, WININET_ProxyPasswordDialog, (LPARAM) &params );
355
356     case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
357     case ERROR_INTERNET_INVALID_CA:
358     case ERROR_INTERNET_POST_IS_NON_SECURE:
359     case ERROR_INTERNET_SEC_CERT_CN_INVALID:
360     case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
361         FIXME("Need to display dialog for error %ld\n", dwError);
362         return ERROR_SUCCESS;
363     }
364     return ERROR_INVALID_PARAMETER;
365 }