dialogs.c 18.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Wininet
 *
 * Copyright 2003 Mike McCormack for CodeWeavers Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 24
#include <stdarg.h>

25 26 27 28 29 30 31 32 33 34
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
#include "wininet.h"
#include "winnetwk.h"
#include "wine/debug.h"
#include "winerror.h"
#define NO_SHLWAPI_STREAM
#include "shlwapi.h"
35
#include "cryptuiapi.h"
36 37 38 39 40 41 42

#include "internet.h"

#include "wine/unicode.h"

#include "resource.h"

43 44
#define MAX_STRING_LEN 1024

45 46 47 48
WINE_DEFAULT_DEBUG_CHANNEL(wininet);

struct WININET_ErrorDlgParams
{
49
    http_request_t *req;
50 51 52 53 54 55 56 57 58 59 60
    HWND       hWnd;
    DWORD      dwError;
    DWORD      dwFlags;
    LPVOID*    lppvData;
};

/***********************************************************************
 *         WININET_GetAuthRealm
 *
 *  Determine the name of the (basic) Authentication realm
 */
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 68 69 70 71 72
    if (proxy)
        query = HTTP_QUERY_PROXY_AUTHENTICATE;
    else
        query = HTTP_QUERY_WWW_AUTHENTICATE;

    /* extract the Realm from the response and show it */
73
    index = 0;
74
    if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) )
75 76 77 78 79 80
        return FALSE;

    /*
     * FIXME: maybe we should check that we're
     * dealing with 'Basic' Authentication
     */
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 89 90 91 92 93 94 95 96
    /* remove quotes */
    p += 7;
    if( *p == '"' )
    {
        p++;
        q = strrchrW( p, '"' );
        if( q )
            *q = 0;
    }
97
    strcpyW( szBuf, p );
98 99 100 101

    return TRUE;
}

102 103 104 105
/* These two are not defined in the public headers */
extern DWORD WINAPI WNetCachePassword(LPSTR,WORD,LPSTR,WORD,BYTE,WORD);
extern DWORD WINAPI WNetGetCachedPassword(LPSTR,WORD,LPSTR,LPWORD,BYTE);

106 107 108
/***********************************************************************
 *         WININET_GetSetPassword
 */
109 110
static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, 
                                    LPCWSTR szRealm, BOOL bSet )
111
{
112 113
    WCHAR szResource[0x80], szUserPass[0x40];
    LPWSTR p;
114 115
    HWND hUserItem, hPassItem;
    DWORD r, dwMagic = 19;
116
    UINT r_len, u_len;
117
    WORD sz;
118 119
    static const WCHAR szColon[] = { ':',0 };
    static const WCHAR szbs[] = { '/', 0 };
120 121 122 123 124

    hUserItem = GetDlgItem( hdlg, IDC_USERNAME );
    hPassItem = GetDlgItem( hdlg, IDC_PASSWORD );

    /* now try fetch the username and password */
125 126 127
    lstrcpyW( szResource, szServer);
    lstrcatW( szResource, szbs);
    lstrcatW( szResource, szRealm);
128

129 130 131 132 133 134
    /*
     * WNetCachePassword is only concerned with the length
     * of the data stored (which we tell it) and it does
     * not use strlen() internally so we can add WCHAR data
     * instead of ASCII data and get it back the same way.
     */
135 136 137
    if( bSet )
    {
        szUserPass[0] = 0;
138 139 140 141 142 143 144 145 146 147 148
        GetWindowTextW( hUserItem, szUserPass, 
                        (sizeof szUserPass-1)/sizeof(WCHAR) );
        lstrcatW(szUserPass, szColon);
        u_len = strlenW( szUserPass );
        GetWindowTextW( hPassItem, szUserPass+u_len, 
                        (sizeof szUserPass)/sizeof(WCHAR)-u_len );

        r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR);
        u_len = (strlenW( szUserPass ) + 1)*sizeof(WCHAR);
        r = WNetCachePassword( (CHAR*)szResource, r_len,
                               (CHAR*)szUserPass, u_len, dwMagic, 0 );
149 150 151 152 153

        return ( r == WN_SUCCESS );
    }

    sz = sizeof szUserPass;
154 155 156
    r_len = (strlenW( szResource ) + 1)*sizeof(WCHAR);
    r = WNetGetCachedPassword( (CHAR*)szResource, r_len,
                               (CHAR*)szUserPass, &sz, dwMagic );
157 158 159
    if( r != WN_SUCCESS )
        return FALSE;

160
    p = strchrW( szUserPass, ':' );
161 162 163
    if( p )
    {
        *p = 0;
164 165
        SetWindowTextW( hUserItem, szUserPass );
        SetWindowTextW( hPassItem, p+1 );
166 167 168 169 170 171
    }

    return TRUE;
}

/***********************************************************************
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 185
    q = heap_strdupW(password);
    if( !q )
186
    {
187
        heap_free(p);
188
        return FALSE;
189
    }
190

191 192
    if (proxy)
    {
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 202
    }
    else
    {
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 215 216 217 218 219 220
}

/***********************************************************************
 *         WININET_ProxyPasswordDialog
 */
static INT_PTR WINAPI WININET_ProxyPasswordDialog(
    HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    HWND hitem;
    struct WININET_ErrorDlgParams *params;
221
    WCHAR szRealm[0x80], szServer[0x80];
222 223 224 225 226 227 228

    if( uMsg == WM_INITDIALOG )
    {
        TRACE("WM_INITDIALOG (%08lx)\n", lParam);

        /* save the parameter list */
        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 240
        hitem = GetDlgItem( hdlg, IDC_PROXY );
        SetWindowTextW( hitem, params->req->session->appInfo->proxy );
241 242 243 244 245 246 247

        WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE );

        return TRUE;
    }

    params = (struct WININET_ErrorDlgParams*)
248
                 GetWindowLongPtrW( hdlg, GWLP_USERDATA );
249 250 251 252 253 254

    switch( uMsg )
    {
    case WM_COMMAND:
        if( wParam == IDOK )
        {
255
            WCHAR username[0x20], password[0x20];
256 257 258 259

            username[0] = 0;
            hitem = GetDlgItem( hdlg, IDC_USERNAME );
            if( hitem )
260
                GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) );
261 262 263 264
            
            password[0] = 0;
            hitem = GetDlgItem( hdlg, IDC_PASSWORD );
            if( hitem )
265
                GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) );
266 267 268

            hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD );
            if( hitem &&
269
                SendMessageW( hitem, BM_GETSTATE, 0, 0 ) &&
270
                WININET_GetAuthRealm( params->req->hdr.hInternet,
271 272
                                      szRealm, sizeof szRealm/sizeof(WCHAR), TRUE) )
                WININET_GetSetPassword( hdlg, params->req->session->appInfo->proxy, szRealm, TRUE );
273
            WININET_SetAuthorization( params->req, username, password, TRUE );
274 275 276 277 278 279 280 281 282 283 284 285 286 287

            EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY );
            return TRUE;
        }
        if( wParam == IDCANCEL )
        {
            EndDialog( hdlg, 0 );
            return TRUE;
        }
        break;
    }
    return FALSE;
}

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
/***********************************************************************
 *         WININET_PasswordDialog
 */
static INT_PTR WINAPI WININET_PasswordDialog(
    HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    HWND hitem;
    struct WININET_ErrorDlgParams *params;
    WCHAR szRealm[0x80], szServer[0x80];

    if( uMsg == WM_INITDIALOG )
    {
        TRACE("WM_INITDIALOG (%08lx)\n", lParam);

        /* save the parameter list */
        params = (struct WININET_ErrorDlgParams*) lParam;
        SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam );

        /* extract the Realm from the response and show it */
307
        if( WININET_GetAuthRealm( params->req->hdr.hInternet,
308 309 310 311 312 313
                                  szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) )
        {
            hitem = GetDlgItem( hdlg, IDC_REALM );
            SetWindowTextW( hitem, szRealm );
        }

314 315
        hitem = GetDlgItem( hdlg, IDC_SERVER );
        SetWindowTextW( hitem, params->req->session->hostName );
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

        WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE );

        return TRUE;
    }

    params = (struct WININET_ErrorDlgParams*)
                 GetWindowLongPtrW( hdlg, GWLP_USERDATA );

    switch( uMsg )
    {
    case WM_COMMAND:
        if( wParam == IDOK )
        {
            WCHAR username[0x20], password[0x20];

            username[0] = 0;
            hitem = GetDlgItem( hdlg, IDC_USERNAME );
            if( hitem )
                GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) );

            password[0] = 0;
            hitem = GetDlgItem( hdlg, IDC_PASSWORD );
            if( hitem )
                GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) );

            hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD );
            if( hitem &&
                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 353 354 355 356 357 358 359 360 361 362 363 364

            EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY );
            return TRUE;
        }
        if( wParam == IDCANCEL )
        {
            EndDialog( hdlg, 0 );
            return TRUE;
        }
        break;
    }
    return FALSE;
}

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
/***********************************************************************
 *         WININET_InvalidCertificateDialog
 */
static INT_PTR WINAPI WININET_InvalidCertificateDialog(
    HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    struct WININET_ErrorDlgParams *params;
    HWND hitem;
    WCHAR buf[1024];

    if( uMsg == WM_INITDIALOG )
    {
        TRACE("WM_INITDIALOG (%08lx)\n", lParam);

        /* save the parameter list */
        params = (struct WININET_ErrorDlgParams*) lParam;
        SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam );

        switch( params->dwError )
        {
        case ERROR_INTERNET_INVALID_CA:
            LoadStringW( WININET_hModule, IDS_CERT_CA_INVALID, buf, 1024 );
            break;
        case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
            LoadStringW( WININET_hModule, IDS_CERT_DATE_INVALID, buf, 1024 );
            break;
        case ERROR_INTERNET_SEC_CERT_CN_INVALID:
            LoadStringW( WININET_hModule, IDS_CERT_CN_INVALID, buf, 1024 );
            break;
        case ERROR_INTERNET_SEC_CERT_ERRORS:
            /* FIXME: We should fetch information about the
             * certificate here and show all the relevant errors.
             */
            LoadStringW( WININET_hModule, IDS_CERT_ERRORS, buf, 1024 );
            break;
        default:
            FIXME( "No message for error %d\n", params->dwError );
            buf[0] = '\0';
        }

        hitem = GetDlgItem( hdlg, IDC_CERT_ERROR );
        SetWindowTextW( hitem, buf );

        return TRUE;
    }

    params = (struct WININET_ErrorDlgParams*)
                 GetWindowLongPtrW( hdlg, GWLP_USERDATA );

    switch( uMsg )
    {
    case WM_COMMAND:
        if( wParam == IDOK )
        {
            if( params->dwFlags & FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS )
            {
421
                http_request_t *req = params->req;
422 423
                DWORD flags, size = sizeof(flags);

424
                InternetQueryOptionW( req->hdr.hInternet, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size );
425 426 427 428 429 430 431 432 433 434 435
                switch( params->dwError )
                {
                case ERROR_INTERNET_INVALID_CA:
                    flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
                    break;
                case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
                    flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
                    break;
                case ERROR_INTERNET_SEC_CERT_CN_INVALID:
                    flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
                    break;
436 437 438
                case ERROR_INTERNET_SEC_CERT_REV_FAILED:
                    flags |= SECURITY_FLAG_IGNORE_REVOCATION;
                    break;
439
                case ERROR_INTERNET_SEC_CERT_ERRORS:
440
                    if(flags & _SECURITY_FLAG_CERT_REV_FAILED)
441 442
                        flags |= SECURITY_FLAG_IGNORE_REVOCATION;
                    if(flags & _SECURITY_FLAG_CERT_INVALID_CA)
443 444 445 446 447
                        flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
                    if(flags & _SECURITY_FLAG_CERT_INVALID_CN)
                        flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
                    if(flags & _SECURITY_FLAG_CERT_INVALID_DATE)
                        flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
448 449
                    break;
                }
450 451 452
                /* FIXME: Use helper function */
                flags |= SECURITY_FLAG_SECURE;
                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 459 460 461 462 463 464 465 466 467 468 469 470 471 472
            return TRUE;
        }
        if( wParam == IDCANCEL )
        {
            TRACE("Pressed cancel.\n");

            EndDialog( hdlg, ERROR_CANCELLED );
            return TRUE;
        }
        break;
    }

    return FALSE;
}

473 474 475 476 477 478 479
/***********************************************************************
 *         InternetErrorDlg
 */
DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest,
                 DWORD dwError, DWORD dwFlags, LPVOID* lppvData)
{
    struct WININET_ErrorDlgParams params;
480 481
    http_request_t *req = NULL;
    DWORD res = ERROR_SUCCESS;
482

483
    TRACE("%p %p %d %08x %p\n", hWnd, hRequest, dwError, dwFlags, lppvData);
484

485 486 487
    if( !hWnd && !(dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI) )
        return ERROR_INVALID_HANDLE;

488 489 490 491 492 493 494 495 496
    if(hRequest) {
        req = (http_request_t*)get_handle_object(hRequest);
        if(!req)
            return ERROR_INVALID_HANDLE;
        if(req->hdr.htype != WH_HHTTPREQ)
            return ERROR_SUCCESS; /* Yes, that was tested */
    }

    params.req = req;
497 498 499 500 501 502 503 504
    params.hWnd = hWnd;
    params.dwError = dwError;
    params.dwFlags = dwFlags;
    params.lppvData = lppvData;

    switch( dwError )
    {
    case ERROR_SUCCESS:
505
    case ERROR_INTERNET_INCORRECT_PASSWORD: {
506
        if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) )
507 508 509
            break;
        if(!req)
            return ERROR_INVALID_HANDLE;
510

511
        switch(req->status_code) {
512
        case HTTP_STATUS_PROXY_AUTH_REQ:
513 514 515
            res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_PROXYDLG ),
                                   hWnd, WININET_ProxyPasswordDialog, (LPARAM) &params );
            break;
516
        case HTTP_STATUS_DENIED:
517
            res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_AUTHDLG ),
518
                                    hWnd, WININET_PasswordDialog, (LPARAM) &params );
519
            break;
520
        default:
521
            WARN("unhandled status %u\n", req->status_code);
522
        }
523 524
        break;
    }
525 526 527 528
    case ERROR_INTERNET_SEC_CERT_ERRORS:
    case ERROR_INTERNET_SEC_CERT_CN_INVALID:
    case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
    case ERROR_INTERNET_INVALID_CA:
529
    case ERROR_INTERNET_SEC_CERT_REV_FAILED:
530 531 532 533 534 535 536
        if( dwFlags & FLAGS_ERROR_UI_FLAGS_NO_UI ) {
            res = ERROR_CANCELLED;
            break;
        }
        if(!req)
            return ERROR_INVALID_HANDLE;

537

538 539 540
        if( dwFlags & ~FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS )
            FIXME("%08x contains unsupported flags.\n", dwFlags);

541 542 543
        res = DialogBoxParamW( WININET_hModule, MAKEINTRESOURCEW( IDD_INVCERTDLG ),
                               hWnd, WININET_InvalidCertificateDialog, (LPARAM) &params );
        break;
544 545
    case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
    case ERROR_INTERNET_POST_IS_NON_SECURE:
546
        FIXME("Need to display dialog for error %d\n", dwError);
547 548 549 550
        res = ERROR_SUCCESS;
        break;
    default:
        res = ERROR_NOT_SUPPORTED;
551
    }
552

553 554 555
    if(req)
        WININET_Release(&req->hdr);
    return res;
556
}
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601

/***********************************************************************
 *           InternetShowSecurityInfoByURLA (@)
 */
BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window)
{
   FIXME("stub: %s %p\n", url, window);
   return FALSE;
}

/***********************************************************************
 *           InternetShowSecurityInfoByURLW (@)
 */
BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window)
{
   FIXME("stub: %s %p\n", debugstr_w(url), window);
   return FALSE;
}

/***********************************************************************
 *           ShowX509EncodedCertificate (@)
 */
DWORD WINAPI ShowX509EncodedCertificate(HWND parent, LPBYTE cert, DWORD len)
{
    PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING,
        cert, len);
    DWORD ret;

    if (certContext)
    {
        CRYPTUI_VIEWCERTIFICATE_STRUCTW view;

        memset(&view, 0, sizeof(view));
        view.hwndParent = parent;
        view.pCertContext = certContext;
        if (CryptUIDlgViewCertificateW(&view, NULL))
            ret = ERROR_SUCCESS;
        else
            ret = GetLastError();
        CertFreeCertificateContext(certContext);
    }
    else
        ret = GetLastError();
    return ret;
}