Ticket #8452: filezilla_3.7.3_http_proxy_digest.patch

File filezilla_3.7.3_http_proxy_digest.patch, 22.6 KB (added by Tommy Wu, 7 years ago)

try digest first, if fail, try basic again

  • src/engine/proxy.cpp

    diff --strip-trailing-cr -Nur filezilla-3.7.3.orig/src/engine/proxy.cpp filezilla-3.7.3/src/engine/proxy.cpp
    old new  
    11#include <filezilla.h>
    22#include "proxy.h"
    33#include <errno.h>
     4#include <wx/tokenzr.h>
    45#include "ControlSocket.h"
    56
    67enum handshake_state
     
    2526    m_pSendBuffer = 0;
    2627    m_pRecvBuffer = 0;
    2728
     29    m_doAuth = 0;
     30
    2831    m_proxyType = unknown;
    2932
    3033    m_can_write = false;
     
    3942    delete [] m_pRecvBuffer;
    4043}
    4144
     45static void AppendSubHex(unsigned char val, wxString& result)
     46{
     47   if (val > 9)
     48   {
     49      result.Append((char)('a'+val-10));
     50   }
     51   else
     52   {
     53      result.Append((char)('0'+val));
     54   }
     55}
     56
     57static void AppendHex(unsigned char val, wxString& result)
     58{
     59   AppendSubHex((val >> 4) & 0xF, result);
     60   AppendSubHex(val&0xF, result);
     61}
     62
     63/*
     64 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
     65 * MD5 Message-Digest Algorithm (RFC 1321).
     66 *
     67 * Homepage:
     68 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
     69 *
     70 * Author:
     71 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
     72 *
     73 * This software was written by Alexander Peslyak in 2001.  No copyright is
     74 * claimed, and the software is hereby placed in the public domain.
     75 * In case this attempt to disclaim copyright and place the software in the
     76 * public domain is deemed null and void, then the software is
     77 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
     78 * general public under the following terms:
     79 *
     80 * Redistribution and use in source and binary forms, with or without
     81 * modification, are permitted.
     82 *
     83 * There's ABSOLUTELY NO WARRANTY, express or implied.
     84 *
     85 * (This is a heavily cut-down "BSD license".)
     86 *
     87 * This differs from Colin Plumb's older public domain implementation in that
     88 * no exactly 32-bit integer data type is required (any 32-bit or wider
     89 * unsigned integer data type will do), there's no compile-time endianness
     90 * configuration, and the function prototypes match OpenSSL's.  No code from
     91 * Colin Plumb's implementation has been reused; this comment merely compares
     92 * the properties of the two independent implementations.
     93 *
     94 * The primary goals of this implementation are portability and ease of use.
     95 * It is meant to be fast, but not as fast as possible.  Some known
     96 * optimizations are not included to reduce source code size and avoid
     97 * compile-time configuration.
     98 */
     99
     100#include <string.h>
     101
     102/* Any 32-bit or wider unsigned integer data type will do */
     103typedef unsigned int MD5_u32plus;
     104
     105typedef struct {
     106    MD5_u32plus lo, hi;
     107    MD5_u32plus a, b, c, d;
     108    unsigned char buffer[64];
     109    MD5_u32plus block[16];
     110} MD5_CTX;
     111
     112/*
     113 * The basic MD5 functions.
     114 *
     115 * F and G are optimized compared to their RFC 1321 definitions for
     116 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
     117 * implementation.
     118 */
     119#define F(x, y, z)          ((z) ^ ((x) & ((y) ^ (z))))
     120#define G(x, y, z)          ((y) ^ ((z) & ((x) ^ (y))))
     121#define H(x, y, z)          ((x) ^ (y) ^ (z))
     122#define I(x, y, z)          ((y) ^ ((x) | ~(z)))
     123
     124/*
     125 * The MD5 transformation for all four rounds.
     126 */
     127#define STEP(f, a, b, c, d, x, t, s) \
     128    (a) += f((b), (c), (d)) + (x) + (t); \
     129    (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
     130    (a) += (b);
     131
     132/*
     133 * SET reads 4 input bytes in little-endian byte order and stores them
     134 * in a properly aligned word in host byte order.
     135 *
     136 * The check for little-endian architectures that tolerate unaligned
     137 * memory accesses is just an optimization.  Nothing will break if it
     138 * doesn't work.
     139 */
     140#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
     141#define SET(n) \
     142    (*(MD5_u32plus *)&ptr[(n) * 4])
     143#define GET(n) \
     144    SET(n)
     145#else
     146#define SET(n) \
     147    (ctx->block[(n)] = \
     148    (MD5_u32plus)ptr[(n) * 4] | \
     149    ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
     150    ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
     151    ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
     152#define GET(n) \
     153    (ctx->block[(n)])
     154#endif
     155
     156/*
     157 * This processes one or more 64-byte data blocks, but does NOT update
     158 * the bit counters.  There are no alignment requirements.
     159 */
     160static void *body(MD5_CTX *ctx, void *data, unsigned long size)
     161{
     162    unsigned char *ptr;
     163    MD5_u32plus a, b, c, d;
     164    MD5_u32plus saved_a, saved_b, saved_c, saved_d;
     165
     166    ptr = (unsigned char *)data;
     167
     168    a = ctx->a;
     169    b = ctx->b;
     170    c = ctx->c;
     171    d = ctx->d;
     172
     173    do {
     174        saved_a = a;
     175        saved_b = b;
     176        saved_c = c;
     177        saved_d = d;
     178
     179/* Round 1 */
     180        STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
     181        STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
     182        STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
     183        STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
     184        STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
     185        STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
     186        STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
     187        STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
     188        STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
     189        STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
     190        STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
     191        STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
     192        STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
     193        STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
     194        STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
     195        STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
     196
     197/* Round 2 */
     198        STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
     199        STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
     200        STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
     201        STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
     202        STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
     203        STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
     204        STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
     205        STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
     206        STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
     207        STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
     208        STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
     209        STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
     210        STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
     211        STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
     212        STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
     213        STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
     214
     215/* Round 3 */
     216        STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
     217        STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
     218        STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
     219        STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
     220        STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
     221        STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
     222        STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
     223        STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
     224        STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
     225        STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
     226        STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
     227        STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
     228        STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
     229        STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
     230        STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
     231        STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
     232
     233/* Round 4 */
     234        STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
     235        STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
     236        STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
     237        STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
     238        STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
     239        STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
     240        STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
     241        STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
     242        STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
     243        STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
     244        STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
     245        STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
     246        STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
     247        STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
     248        STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
     249        STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
     250
     251        a += saved_a;
     252        b += saved_b;
     253        c += saved_c;
     254        d += saved_d;
     255
     256        ptr += 64;
     257    } while (size -= 64);
     258
     259    ctx->a = a;
     260    ctx->b = b;
     261    ctx->c = c;
     262    ctx->d = d;
     263
     264    return ptr;
     265}
     266
     267void MD5_Init(MD5_CTX *ctx)
     268{
     269    ctx->a = 0x67452301;
     270    ctx->b = 0xefcdab89;
     271    ctx->c = 0x98badcfe;
     272    ctx->d = 0x10325476;
     273
     274    ctx->lo = 0;
     275    ctx->hi = 0;
     276}
     277
     278void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
     279{
     280    MD5_u32plus saved_lo;
     281    unsigned long used, free;
     282
     283    saved_lo = ctx->lo;
     284    if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
     285        ctx->hi++;
     286    ctx->hi += size >> 29;
     287
     288    used = saved_lo & 0x3f;
     289
     290    if (used) {
     291        free = 64 - used;
     292
     293        if (size < free) {
     294            memcpy(&ctx->buffer[used], data, size);
     295            return;
     296        }
     297
     298        memcpy(&ctx->buffer[used], data, free);
     299        data = (unsigned char *)data + free;
     300        size -= free;
     301        body(ctx, ctx->buffer, 64);
     302    }
     303
     304    if (size >= 64) {
     305        data = body(ctx, data, size & ~(unsigned long)0x3f);
     306        size &= 0x3f;
     307    }
     308
     309    memcpy(ctx->buffer, data, size);
     310}
     311
     312void MD5_Final(unsigned char *result, MD5_CTX *ctx)
     313{
     314    unsigned long used, free;
     315
     316    used = ctx->lo & 0x3f;
     317
     318    ctx->buffer[used++] = 0x80;
     319
     320    free = 64 - used;
     321
     322    if (free < 8) {
     323        memset(&ctx->buffer[used], 0, free);
     324        body(ctx, ctx->buffer, 64);
     325        used = 0;
     326        free = 64;
     327    }
     328
     329    memset(&ctx->buffer[used], 0, free - 8);
     330
     331    ctx->lo <<= 3;
     332    ctx->buffer[56] = ctx->lo;
     333    ctx->buffer[57] = ctx->lo >> 8;
     334    ctx->buffer[58] = ctx->lo >> 16;
     335    ctx->buffer[59] = ctx->lo >> 24;
     336    ctx->buffer[60] = ctx->hi;
     337    ctx->buffer[61] = ctx->hi >> 8;
     338    ctx->buffer[62] = ctx->hi >> 16;
     339    ctx->buffer[63] = ctx->hi >> 24;
     340
     341    body(ctx, ctx->buffer, 64);
     342
     343    result[0] = ctx->a;
     344    result[1] = ctx->a >> 8;
     345    result[2] = ctx->a >> 16;
     346    result[3] = ctx->a >> 24;
     347    result[4] = ctx->b;
     348    result[5] = ctx->b >> 8;
     349    result[6] = ctx->b >> 16;
     350    result[7] = ctx->b >> 24;
     351    result[8] = ctx->c;
     352    result[9] = ctx->c >> 8;
     353    result[10] = ctx->c >> 16;
     354    result[11] = ctx->c >> 24;
     355    result[12] = ctx->d;
     356    result[13] = ctx->d >> 8;
     357    result[14] = ctx->d >> 16;
     358    result[15] = ctx->d >> 24;
     359
     360    memset(ctx, 0, sizeof(*ctx));
     361}
     362
     363static wxString ComputeMD5(const char *buf, unsigned int len)
     364{
     365    MD5_CTX ctx;
     366    unsigned char signature[16];
     367
     368    MD5_Init(&ctx);
     369    MD5_Update(&ctx, (void *)buf, len);
     370    MD5_Final(signature, &ctx);
     371
     372    wxString result;
     373    for (int j = 0; j < (int)sizeof signature; j++)
     374    {
     375        AppendHex(signature[j], result);
     376    }
     377
     378    return result;
     379}
     380
    42381static wxString base64encode(const wxString& str)
    43382{
    44383    // Code shamelessly taken from wxWidgets and adopted to encode UTF-8 strings.
     
    96435    {
    97436        m_handshakeState = http_wait;
    98437
    99 #if wxUSE_UNICODE
    100         wxWX2MBbuf challenge;
    101 #else
    102         const wxWX2MBbuf challenge;
    103 #endif
    104         int challenge_len;
    105         if (user != _T(""))
    106         {
    107             challenge = base64encode(user + _T(":") + pass).mb_str(wxConvUTF8);
    108             challenge_len = strlen(challenge);
    109         }
    110         else
    111         {
    112             challenge = (size_t)0;
    113             challenge_len = 0;
    114         }
    115 
    116438        // Bit oversized, but be on the safe side
    117         m_pSendBuffer = new char[70 + strlen(host_raw) * 2 + 2*5 + challenge_len + 23];
     439        m_pSendBuffer = new char[70 + strlen(host_raw) * 2 + 2*5 + 23];
    118440
    119         if (!challenge)
    120         {
    121             m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nUser-Agent: FileZilla\r\n\r\n",
    122                 (const char*)host_raw, port,
    123                 (const char*)host_raw, port);
    124         }
    125         else
    126         {
    127             m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\nUser-Agent: FileZilla\r\n\r\n",
    128                 (const char*)host_raw, port,
    129                 (const char*)host_raw, port,
    130                 (const char*)challenge);
    131         }
     441        m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nUser-Agent: FileZilla\r\n\r\n",
     442            (const char*)host_raw, port,
     443            (const char*)host_raw, port);
    132444
    133445        m_pRecvBuffer = new char[4096];
    134446        m_recvBufferLen = 4096;
     
    302614            if (!end)
    303615                continue;
    304616
     617            unsigned long int nContentLength = 0;
     618            bool bUseBasic = false;
     619            bool bUseDigest = false;
     620            wxString digestStr = _T("");
     621            wxString authStr = _T("");
     622            wxString header_str(m_pRecvBuffer, wxConvLocal, m_recvBufferPos);
     623            wxStringTokenizer tkz(header_str, wxT("\r\n"));
     624
     625            while (tkz.HasMoreTokens())
     626            {
     627                wxString token = tkz.GetNextToken();
     628                if (token.Mid(0, 15).Lower() == _T("content-length:"))
     629                {
     630                    token.Mid(15).Trim(true).Trim(false).ToULong(&nContentLength);
     631                    continue;
     632                }
     633                if (token.Mid(0, 26).Lower() == _T("proxy-authenticate: basic "))
     634                {
     635                    bUseBasic = true;
     636                    continue;
     637                }
     638                if (token.Mid(0, 27).Lower() == _T("proxy-authenticate: digest "))
     639                {
     640                    authStr = token.Mid(27);
     641                    bUseDigest = true;
     642                    continue;
     643                }
     644            }
     645
     646            // read body
     647            unsigned long int nBodyLength = 0;
     648            char *pBody = new char[nContentLength];
     649            while (nBodyLength < nContentLength) {
     650                int read;
     651
     652                do_read = nContentLength - nBodyLength;
     653
     654                read = m_pSocket->Read(pBody + nBodyLength, do_read, error);
     655                if (read == -1)
     656                {
     657                    if (error != EAGAIN)
     658                    {
     659                        delete [] pBody;
     660                        m_proxyState = noconn;
     661                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, error);
     662                        CSocketEventDispatcher::Get().SendEvent(evt);
     663                    }
     664                    else
     665                        m_can_read = false;
     666                    continue;
     667                }
     668                if (!read)
     669                {
     670                    delete [] pBody;
     671                    m_proxyState = noconn;
     672                    CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, ECONNABORTED);
     673                    CSocketEventDispatcher::Get().SendEvent(evt);
     674                    return;
     675                }
     676                if (m_pSendBuffer)
     677                {
     678                    delete [] pBody;
     679                    m_proxyState = noconn;
     680                    m_pOwner->LogMessage(Debug_Warning, _T("Incoming data before requst fully sent"));
     681                    CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, ECONNABORTED);
     682                    CSocketEventDispatcher::Get().SendEvent(evt);
     683                    return;
     684                }
     685                nBodyLength += read;
     686            }
     687
    305688            end = strchr(m_pRecvBuffer, '\r');
    306689            wxASSERT(end);
    307690            *end = 0;
    308691            wxString reply(m_pRecvBuffer, wxConvUTF8);
    309692            m_pOwner->LogMessage(Response, _("Proxy reply: %s"), reply.c_str());
    310693
     694            if (reply.Left(12) == _T("HTTP/1.1 401") || reply.Left(12) == _T("HTTP/1.1 407") ||
     695                reply.Left(12) == _T("HTTP/1.0 401") || reply.Left(12) == _T("HTTP/1.0 407"))
     696            {
     697                if (m_doAuth == 1) {
     698                    // need to try BASIC when DIGEST failed
     699                    bUseDigest = false;
     700                    bUseBasic = true;
     701                }
     702                if (m_doAuth || m_user == _T(""))
     703                {
     704                    delete [] pBody;
     705                    m_pOwner->LogMessage(Debug_Warning, _("already m_doAuth (%d), or m_user is empty (%s)"), m_doAuth, m_user.c_str());
     706                    m_proxyState = noconn;
     707                    CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close, ECONNRESET);
     708                    CSocketEventDispatcher::Get().SendEvent(evt);
     709                    return;
     710                }
     711
     712                if (bUseDigest)
     713                {
     714                    wxString realm = _T("");
     715                    wxString nonce = _T("");
     716                    wxString qop = _T("");
     717                    wxStringTokenizer tkz2(authStr, wxT(","));
     718                    while (tkz2.HasMoreTokens())
     719                    {
     720                        wxString token2 = tkz2.GetNextToken();
     721                        wxString name = _T("");
     722                        wxString value = _T("");
     723                        wxStringTokenizer tkz3(token2, wxT("="));
     724                        while (tkz3.HasMoreTokens())
     725                        {
     726                            wxString token3 = tkz3.GetNextToken();
     727                            if (name == _T(""))
     728                            {
     729                                name = token3.Lower().Trim(true).Trim(false);
     730                                continue;
     731                            }
     732                            if (token3.Left(1) == _T("\""))
     733                                value = token3.Mid(1, token3.Len()-2).Trim(true).Trim(false);
     734                            else
     735                                value = token3.Trim(true).Trim(false);
     736                            break;
     737                        }
     738                        if (name == _T("realm"))
     739                            realm = value;
     740                        else if (name == _T("nonce"))
     741                            nonce = value;
     742                        else if (name == _T("qop"))
     743                            qop = value;
     744                    }
     745                    if (realm == _T("") || nonce == _T(""))
     746                    {
     747                        delete [] pBody;
     748                        m_pOwner->LogMessage(Debug_Warning, _T("no realm or nonce"));
     749                        m_proxyState = conn;
     750                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     751                        CSocketEventDispatcher::Get().SendEvent(evt);
     752                        return;
     753                    }
     754                    // HA1 = md5(username:realm:password)
     755                    // if qop = auth or no qop
     756                    // HA2 = md5(method:digestURI)
     757                    // if qop = auth-int
     758                    // HA2 = md5(method:digestURI:md5(body))
     759                    // if qop = auth or auth-int
     760                    // response = md5(HA1:nonce:nonceCount:clientNonce:qop:HA2)
     761                    // if no qop
     762                    // response = md5(HA1:nonce:HA2)
     763                    wxString ha1, ha2, response;
     764                    wxString s;
     765                    bool bAuth = false;
     766                    bool bAuthInt = false;
     767
     768                    if (qop != _T(""))
     769                    {
     770                        wxStringTokenizer tkz4(qop, wxT(","));
     771                        while (tkz4.HasMoreTokens())
     772                        {
     773                            wxString token4 = tkz4.GetNextToken();
     774                            if (token4 == _T("auth"))
     775                                bAuth = true;
     776                            if (token4 == _T("auth-int"))
     777                                bAuthInt = true;
     778                        }
     779                    }
     780
     781                    s = wxString::Format(_T("%s:%s:%s"), m_user.c_str(), realm.c_str(), m_pass.c_str());
     782                    const wxWX2MBbuf s_raw = s.mb_str(wxConvUTF8);
     783                    ha1 = ComputeMD5((const char *)s_raw, strlen(s_raw));
     784
     785                    wxString uri = _T("");
     786                    if (qop == _T("") || bAuth)
     787                    {
     788                        uri = wxString::Format(_T("%s:%u"), m_host.c_str(), m_port);
     789                        s = wxString::Format(_T("CONNECT:%s"), uri.c_str());
     790                        const wxWX2MBbuf s_raw = s.mb_str(wxConvUTF8);
     791                        ha2 = ComputeMD5((const char *)s_raw, strlen(s_raw));
     792                    }
     793                    else if (bAuthInt)
     794                    {
     795                        uri = wxString::Format(_T("%s:%u"), m_host.c_str(), m_port);
     796                        wxString bodyMD5 = ComputeMD5((const char *)pBody, nBodyLength);
     797                        s = wxString::Format(_T("CONNECT:%s:%s"), uri.c_str(), bodyMD5.c_str());
     798                        const wxWX2MBbuf s_raw = s.mb_str(wxConvLocal);
     799                        ha2 = ComputeMD5((const char *)s_raw, strlen(s_raw));
     800                    }
     801                    else
     802                    {
     803                        delete [] pBody;
     804                        m_pOwner->LogMessage(Debug_Warning, _T("unknown qop: %s"), qop.c_str());
     805                        m_proxyState = conn;
     806                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     807                        CSocketEventDispatcher::Get().SendEvent(evt);
     808                        return;
     809                    }
     810
     811                    // we don't need body now
     812                    delete [] pBody;
     813                    if (bAuth || bAuthInt)
     814                    {
     815                        wxString clientNonce = wxString::Format(_T("%04x%04x"), GetRandomNumber(0, 0xffff), GetRandomNumber(0, 0xffff));
     816
     817                        s = wxString::Format(_T("%s:%s:%s:%s:%s:%s"),
     818                            ha1.c_str(),
     819                            nonce.c_str(),
     820                            _T("00000001"),
     821                            clientNonce.c_str(),
     822                            bAuth ? _T("auth") : _T("auth-int"),
     823                            ha2.c_str());
     824                        const wxWX2MBbuf s_raw = s.mb_str(wxConvLocal);
     825                        response = ComputeMD5((const char *)s_raw, strlen(s_raw));
     826
     827                        digestStr = wxString::Format(_T("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\", qop=%s, nc=00000001, cnonce=\"%s\""),
     828                            m_user.c_str(),
     829                            realm.c_str(),
     830                            nonce.c_str(),
     831                            uri.c_str(),
     832                            response.c_str(),
     833                            bAuth ? _T("auth") : _T("auth-int"),
     834                            clientNonce.c_str());
     835                    }
     836                    else
     837                    {
     838                        s = wxString::Format(_T("%s:%s:%s"),
     839                            ha1.c_str(),
     840                            nonce.c_str(),
     841                            ha2.c_str());
     842                        const wxWX2MBbuf s_raw = s.mb_str(wxConvLocal);
     843                        response = ComputeMD5((const char *)s_raw, strlen(s_raw));
     844
     845                        digestStr = wxString::Format(_T("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\""),
     846                            m_user.c_str(),
     847                            realm.c_str(),
     848                            nonce.c_str(),
     849                            uri.c_str(),
     850                            response.c_str());
     851                    }
     852
     853                    if (bUseBasic)
     854                        m_doAuth = 1;   // try BASIC later if DIGEST failed
     855                    else
     856                        m_doAuth = 2;
     857                                m_recvBufferPos = 0;
     858
     859                    const wxWX2MBbuf host_raw = m_host.mb_str(wxConvUTF8);
     860                    const wxWX2MBbuf digest_raw = digestStr.mb_str(wxConvLocal);
     861
     862                    int challenge_len = digestStr.Len();
     863
     864                    m_pOwner->LogMessage(Status, _("Sending CONNECT with Digest Authorization"));
     865
     866                                // Bit oversized, but be on the safe side
     867                                m_pSendBuffer = new char[70 + m_host.Len() * 2 + 2*5 + challenge_len * 2 + 23 + 40];
     868
     869                    m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: %s\r\nUser-Agent: FileZilla\r\n\r\n",
     870                        (const char*)host_raw, m_port,
     871                        (const char*)host_raw, m_port,
     872                        (const char*)digest_raw);
     873
     874                    wxString host = m_pSocket->GetPeerIP();
     875                    unsigned int port = m_pSocket->GetRemotePort(error);
     876
     877                    m_pSocket->Close();
     878                    int res = m_pSocket->Connect(host, port);
     879                    // Treat success same as EINPROGRESS, we wait for connect notification in any case
     880                    if (res && res != EINPROGRESS)
     881                    {
     882                        m_pOwner->LogMessage(Debug_Warning, _T("connect error?"));
     883                        m_proxyState = conn;
     884                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     885                        CSocketEventDispatcher::Get().SendEvent(evt);
     886                        return;
     887                    }
     888                    return;
     889                }
     890
     891                if (bUseBasic)
     892                {
     893                    // we don't need body for this
     894                    delete [] pBody;
     895                    m_doAuth = 2;
     896                                m_recvBufferPos = 0;
     897
     898#if wxUSE_UNICODE
     899                    wxWX2MBbuf challenge;
     900#else
     901                    const wxWX2MBbuf challenge;
     902#endif
     903                    const wxWX2MBbuf host_raw = m_host.mb_str(wxConvUTF8);
     904                    int challenge_len;
     905
     906                    challenge = base64encode(m_user + _T(":") + m_pass).mb_str(wxConvUTF8);
     907                    challenge_len = strlen(challenge);
     908
     909                    m_pOwner->LogMessage(Status, _("Sending CONNECT with Basic Authorization"));
     910                    // Bit oversized, but be on the safe side
     911                    m_pSendBuffer = new char[70 + strlen(host_raw) * 2 + 2*5 + challenge_len + 23];
     912
     913                    m_sendBufferLen = sprintf(m_pSendBuffer, "CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\nUser-Agent: FileZilla\r\n\r\n",
     914                        (const char*)host_raw, m_port,
     915                        (const char*)host_raw, m_port,
     916                        (const char*)challenge);
     917
     918                    wxString host = m_pSocket->GetPeerIP();
     919                    unsigned int port = m_pSocket->GetRemotePort(error);
     920
     921                    m_pSocket->Close();
     922                    int res = m_pSocket->Connect(host, port);
     923                    // Treat success same as EINPROGRESS, we wait for connect notification in any case
     924                    if (res && res != EINPROGRESS)
     925                    {
     926                        m_pOwner->LogMessage(Debug_Warning, _T("connect error?"));
     927                        m_proxyState = conn;
     928                        CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection, 0);
     929                        CSocketEventDispatcher::Get().SendEvent(evt);
     930                        return;
     931                    }
     932                    return;
     933                }
     934                // other authentication method?
     935            }
     936            delete [] pBody;
     937
    311938            if (reply.Left(10) != _T("HTTP/1.1 2") && reply.Left(10) != _T("HTTP/1.0 2"))
    312939            {
    313940                m_proxyState = noconn;
  • src/engine/proxy.h

    diff --strip-trailing-cr -Nur filezilla-3.7.3.orig/src/engine/proxy.h filezilla-3.7.3/src/engine/proxy.h
    old new  
    6565    int m_recvBufferPos;
    6666    int m_recvBufferLen;
    6767
     68    int m_doAuth;
     69
    6870    void OnSocketEvent(CSocketEvent& event);
    6971    void OnReceive();
    7072    void OnSend();