src/network/kernel/qauthenticator.cpp
changeset 33 3e2da88830cd
parent 18 2f34d5167611
child 37 758a864f9613
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
    48 #include <qhttp.h>
    48 #include <qhttp.h>
    49 #include <qiodevice.h>
    49 #include <qiodevice.h>
    50 #include <qdatastream.h>
    50 #include <qdatastream.h>
    51 #include <qendian.h>
    51 #include <qendian.h>
    52 #include <qstring.h>
    52 #include <qstring.h>
       
    53 #include <qdatetime.h>
       
    54 
    53 
    55 
    54 QT_BEGIN_NAMESPACE
    56 QT_BEGIN_NAMESPACE
    55 
    57 
    56 #include "../../3rdparty/des/des.cpp"
    58 #include "../../3rdparty/des/des.cpp"
    57 
    59 
    81     \o Digest-MD5
    83     \o Digest-MD5
    82   \endlist
    84   \endlist
    83 
    85 
    84   Note that, in particular, NTLM version 2 is not supported.
    86   Note that, in particular, NTLM version 2 is not supported.
    85 
    87 
       
    88   \section1 Options
       
    89 
       
    90   In addition to the username and password required for authentication, a
       
    91   QAuthenticator object can also contain additional options. The
       
    92   options() function can be used to query incoming options sent by
       
    93   the server; the setOption() function can
       
    94   be used to set outgoing options, to be processed by the authenticator
       
    95   calculation. The options accepted and provided depend on the authentication
       
    96   type (see method()).
       
    97 
       
    98   The following tables list known incoming options as well as accepted
       
    99   outgoing options. The list of incoming options is not exhaustive, since
       
   100   servers may include additional information at any time. The list of
       
   101   outgoing options is exhaustive, however, and no unknown options will be
       
   102   treated or sent back to the server.
       
   103 
       
   104   \section2 Basic
       
   105 
       
   106   \table
       
   107     \header \o Option \o Direction \o Description
       
   108     \row \o \tt{realm} \o Incoming \o Contains the realm of the authentication, the same as realm()
       
   109   \endtable
       
   110 
       
   111   The Basic authentication mechanism supports no outgoing options.
       
   112 
       
   113   \section2 NTLM version 1
       
   114 
       
   115   The NTLM authentication mechanism currently supports no incoming or outgoing options.
       
   116 
       
   117   \section2 Digest-MD5
       
   118 
       
   119   \table
       
   120     \header \o Option \o Direction \o Description
       
   121     \row \o \tt{realm} \o Incoming \o Contains the realm of the authentication, the same as realm()
       
   122   \endtable
       
   123 
       
   124   The Digest-MD5 authentication mechanism supports no outgoing options.
       
   125 
    86   \sa QSslSocket
   126   \sa QSslSocket
    87 */
   127 */
    88 
   128 
    89 
   129 
    90 /*!
   130 /*!
   136     if (d == other.d)
   176     if (d == other.d)
   137         return true;
   177         return true;
   138     return d->user == other.d->user
   178     return d->user == other.d->user
   139         && d->password == other.d->password
   179         && d->password == other.d->password
   140         && d->realm == other.d->realm
   180         && d->realm == other.d->realm
   141         && d->method == other.d->method;
   181         && d->method == other.d->method
       
   182         && d->options == other.d->options;
   142 }
   183 }
   143 
   184 
   144 /*!
   185 /*!
   145     \fn bool QAuthenticator::operator!=(const QAuthenticator &other) const
   186     \fn bool QAuthenticator::operator!=(const QAuthenticator &other) const
   146 
   187 
   160   Sets the \a user used for authentication.
   201   Sets the \a user used for authentication.
   161 */
   202 */
   162 void QAuthenticator::setUser(const QString &user)
   203 void QAuthenticator::setUser(const QString &user)
   163 {
   204 {
   164     detach();
   205     detach();
   165     d->user = user;
   206 
       
   207     int separatorPosn = 0;
       
   208     separatorPosn = user.indexOf(QLatin1String("\\"));
       
   209 
       
   210     if (separatorPosn == -1) {
       
   211         //No domain name present
       
   212         d->user = user;
       
   213     } else {
       
   214         //domain name is present
       
   215         d->realm = user.left(separatorPosn);
       
   216         d->user = user.mid(separatorPosn+1);
       
   217     }
   166 }
   218 }
   167 
   219 
   168 /*!
   220 /*!
   169   returns the password used for authentication.
   221   returns the password used for authentication.
   170 */
   222 */
   203 QString QAuthenticator::realm() const
   255 QString QAuthenticator::realm() const
   204 {
   256 {
   205     return d ? d->realm : QString();
   257     return d ? d->realm : QString();
   206 }
   258 }
   207 
   259 
   208 
   260 /*!
   209 /*!
   261     \since 4.7
   210   returns true if the authenticator is null.
   262     Returns the value related to option \a opt if it was set by the server.
       
   263     See \l{QAuthenticator#Options} for more information on incoming options.
       
   264     If option \a opt isn't found, an invalid QVariant will be returned.
       
   265 
       
   266     \sa options(), QAuthenticator#Options
       
   267 */
       
   268 QVariant QAuthenticator::option(const QString &opt) const
       
   269 {
       
   270     return d ? d->options.value(opt) : QVariant();
       
   271 }
       
   272 
       
   273 /*!
       
   274     \since 4.7
       
   275     Returns all incoming options set in this QAuthenticator object by parsing
       
   276     the server reply. See \l{QAuthenticator#Options} for more information
       
   277     on incoming options.
       
   278 
       
   279     \sa option(), QAuthenticator#Options
       
   280 */
       
   281 QVariantHash QAuthenticator::options() const
       
   282 {
       
   283     return d ? d->options : QVariantHash();
       
   284 }
       
   285 
       
   286 /*!
       
   287     \since 4.7
       
   288 
       
   289     Sets the outgoing option \a opt to value \a value.
       
   290     See \l{QAuthenticator#Options} for more information on outgoing options.
       
   291 
       
   292     \sa options(), option(), QAuthenticator#Options
       
   293 */
       
   294 void QAuthenticator::setOption(const QString &opt, const QVariant &value)
       
   295 {
       
   296     detach();
       
   297     d->options.insert(opt, value);
       
   298 }
       
   299 
       
   300 
       
   301 /*!
       
   302     Returns true if the authenticator is null.
   211 */
   303 */
   212 bool QAuthenticator::isNull() const
   304 bool QAuthenticator::isNull() const
   213 {
   305 {
   214     return !d;
   306     return !d;
   215 }
   307 }
   226 }
   318 }
   227 
   319 
   228 #ifndef QT_NO_HTTP
   320 #ifndef QT_NO_HTTP
   229 void QAuthenticatorPrivate::parseHttpResponse(const QHttpResponseHeader &header, bool isProxy)
   321 void QAuthenticatorPrivate::parseHttpResponse(const QHttpResponseHeader &header, bool isProxy)
   230 {
   322 {
   231     QList<QPair<QString, QString> > values = header.values();
   323     const QList<QPair<QString, QString> > values = header.values();
       
   324     QList<QPair<QByteArray, QByteArray> > rawValues;
       
   325 
       
   326     QList<QPair<QString, QString> >::const_iterator it, end;
       
   327     for (it = values.constBegin(), end = values.constEnd(); it != end; ++it)
       
   328         rawValues.append(qMakePair(it->first.toLatin1(), it->second.toUtf8()));
       
   329 
       
   330     // continue in byte array form
       
   331     parseHttpResponse(rawValues, isProxy);
       
   332 }
       
   333 #endif
       
   334 
       
   335 void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy)
       
   336 {
   232     const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
   337     const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
   233 
   338 
   234     method = None;
   339     method = None;
   235     /*
   340     /*
   236       Fun from the HTTP 1.1 specs, that we currently ignore:
   341       Fun from the HTTP 1.1 specs, that we currently ignore:
   240       or if more than one WWW-Authenticate header field is provided, the
   345       or if more than one WWW-Authenticate header field is provided, the
   241       contents of a challenge itself can contain a comma-separated list of
   346       contents of a challenge itself can contain a comma-separated list of
   242       authentication parameters.
   347       authentication parameters.
   243     */
   348     */
   244 
   349 
   245     QString headerVal;
   350     QByteArray headerVal;
   246     for (int i = 0; i < values.size(); ++i) {
   351     for (int i = 0; i < values.size(); ++i) {
   247         const QPair<QString, QString> &current = values.at(i);
   352         const QPair<QByteArray, QByteArray> &current = values.at(i);
   248         if (current.first.toLower() != QLatin1String(search))
   353         if (current.first.toLower() != search)
   249             continue;
   354             continue;
   250         QString str = current.second;
   355         QByteArray str = current.second.toLower();
   251         if (method < Basic && str.startsWith(QLatin1String("Basic"), Qt::CaseInsensitive)) {
   356         if (method < Basic && str.startsWith("basic")) {
   252             method = Basic; headerVal = str.mid(6);
   357             method = Basic;
   253         } else if (method < Ntlm && str.startsWith(QLatin1String("NTLM"), Qt::CaseInsensitive)) {
   358             headerVal = current.second.mid(6);
       
   359         } else if (method < Ntlm && str.startsWith("ntlm")) {
   254             method = Ntlm;
   360             method = Ntlm;
   255             headerVal = str.mid(5);
   361             headerVal = current.second.mid(5);
   256         } else if (method < DigestMd5 && str.startsWith(QLatin1String("Digest"), Qt::CaseInsensitive)) {
   362         } else if (method < DigestMd5 && str.startsWith("digest")) {
   257             method = DigestMd5;
   363             method = DigestMd5;
   258             headerVal = str.mid(7);
   364             headerVal = current.second.mid(7);
   259         }
   365         }
   260     }
   366     }
   261 
   367 
   262     challenge = headerVal.trimmed().toLatin1();
   368     challenge = headerVal.trimmed();
   263     QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
   369     QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
   264 
   370 
   265     switch(method) {
   371     switch(method) {
   266     case Basic:
   372     case Basic:
   267         realm = QString::fromLatin1(options.value("realm"));
   373         if(realm.isEmpty())
       
   374             this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
   268         if (user.isEmpty())
   375         if (user.isEmpty())
   269             phase = Done;
   376             phase = Done;
   270         break;
   377         break;
   271     case Ntlm:
   378     case Ntlm:
   272         // #### extract from header
   379         // #### extract from header
   273         realm.clear();
       
   274         break;
   380         break;
   275     case DigestMd5: {
   381     case DigestMd5: {
   276         realm = QString::fromLatin1(options.value("realm"));
   382         if(realm.isEmpty())
       
   383             this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
   277         if (options.value("stale").toLower() == "true")
   384         if (options.value("stale").toLower() == "true")
   278             phase = Start;
   385             phase = Start;
   279         if (user.isEmpty())
   386         if (user.isEmpty())
   280             phase = Done;
   387             phase = Done;
   281         break;
   388         break;
   284         realm.clear();
   391         realm.clear();
   285         challenge = QByteArray();
   392         challenge = QByteArray();
   286         phase = Invalid;
   393         phase = Invalid;
   287     }
   394     }
   288 }
   395 }
   289 #endif
       
   290 
   396 
   291 QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path)
   397 QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path)
   292 {
   398 {
   293     QByteArray response;
   399     QByteArray response;
   294     const char *methodString = 0;
   400     const char *methodString = 0;
   659 /*
   765 /*
   660  * Indicates that 56-bit encryption is supported.
   766  * Indicates that 56-bit encryption is supported.
   661  */
   767  */
   662 #define NTLMSSP_NEGOTIATE_56 0x80000000
   768 #define NTLMSSP_NEGOTIATE_56 0x80000000
   663 
   769 
       
   770 /*
       
   771  * AvId values
       
   772  */
       
   773 #define AVTIMESTAMP 7
       
   774 
       
   775 //#define NTLMV1_CLIENT
       
   776 
       
   777 
       
   778 //************************Global variables***************************
       
   779 
       
   780 const int blockSize = 64; //As per RFC2104 Block-size is 512 bits
       
   781 const int nDigestLen = 16; //Trunctaion Length of the Hmac-Md5 digest
       
   782 const quint8 respversion = 1;
       
   783 const quint8 hirespversion = 1;
   664 
   784 
   665 /* usage:
   785 /* usage:
   666    // fill up ctx with what we know.
   786    // fill up ctx with what we know.
   667    QByteArray response = qNtlmPhase1(ctx);
   787    QByteArray response = qNtlmPhase1(ctx);
   668    // send response (b64 encoded??)
   788    // send response (b64 encoded??)
   801         type = 0xffffffff;
   921         type = 0xffffffff;
   802     }
   922     }
   803 
   923 
   804     // extracted
   924     // extracted
   805     QString targetNameStr, targetInfoStr;
   925     QString targetNameStr, targetInfoStr;
       
   926     QByteArray targetInfoBuff;
   806 };
   927 };
   807 
   928 
   808 
   929 
   809 
   930 
   810 class QNtlmPhase3Block : public QNtlmPhase3BlockBase {  // response
   931 class QNtlmPhase3Block : public QNtlmPhase3BlockBase {  // response
   816     }
   937     }
   817 
   938 
   818     // extracted
   939     // extracted
   819     QByteArray lmResponseBuf, ntlmResponseBuf;
   940     QByteArray lmResponseBuf, ntlmResponseBuf;
   820     QString domainStr, userStr, workstationStr, sessionKeyStr;
   941     QString domainStr, userStr, workstationStr, sessionKeyStr;
       
   942     QByteArray v2Hash;
   821 };
   943 };
   822 
   944 
   823 
   945 
   824 static QDataStream& operator<<(QDataStream& s, const QNtlmPhase1Block& b) {
   946 static QDataStream& operator<<(QDataStream& s, const QNtlmPhase1Block& b) {
   825     bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE);
   947     bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE);
   897         d[i] = qFromLittleEndian(d[i]);
  1019         d[i] = qFromLittleEndian(d[i]);
   898     }
  1020     }
   899     return QString((const QChar *)src.data(), src.size()/2);
  1021     return QString((const QChar *)src.data(), src.size()/2);
   900 }
  1022 }
   901 
  1023 
   902 
  1024 #ifdef NTLMV1_CLIENT
   903 static QByteArray qEncodeNtlmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
  1025 static QByteArray qEncodeNtlmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
   904 {
  1026 {
   905     QCryptographicHash md4(QCryptographicHash::Md4);
  1027     QCryptographicHash md4(QCryptographicHash::Md4);
   906     QByteArray asUcs2Le = qStringAsUcs2Le(ctx->password);
  1028     QByteArray asUcs2Le = qStringAsUcs2Le(ctx->password);
   907     md4.addData(asUcs2Le.data(), asUcs2Le.size());
  1029     md4.addData(asUcs2Le.data(), asUcs2Le.size());
   939     deshash((unsigned char *)rc.data() + 16, (unsigned char *)hash.data() + 14, ch.challenge);
  1061     deshash((unsigned char *)rc.data() + 16, (unsigned char *)hash.data() + 14, ch.challenge);
   940 
  1062 
   941     hash.fill(0);
  1063     hash.fill(0);
   942     return rc;
  1064     return rc;
   943 }
  1065 }
   944 
  1066 #endif
       
  1067 
       
  1068 /*********************************************************************
       
  1069 * Function Name: qEncodeHmacMd5
       
  1070 * Params:
       
  1071 *    key:   Type - QByteArray
       
  1072 *         - It is the Authentication key
       
  1073 *    message:   Type - QByteArray
       
  1074 *         - This is the actual message which will be encoded
       
  1075 *           using HMacMd5 hash algorithm
       
  1076 *
       
  1077 * Return Value:
       
  1078 *    hmacDigest:   Type - QByteArray
       
  1079 *
       
  1080 * Description:
       
  1081 *    This function will be used to encode the input message using
       
  1082 *    HMacMd5 hash algorithm.
       
  1083 *
       
  1084 *    As per the RFC2104 the HMacMd5 algorithm can be specified
       
  1085 *        ---------------------------------------
       
  1086 *         MD5(K XOR opad, MD5(K XOR ipad, text))
       
  1087 *        ---------------------------------------
       
  1088 *
       
  1089 *********************************************************************/
       
  1090 QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
       
  1091 {
       
  1092     Q_ASSERT_X(!(message.isEmpty()),"qEncodeHmacMd5", "Empty message check");
       
  1093     Q_ASSERT_X(!(key.isEmpty()),"qEncodeHmacMd5", "Empty key check");
       
  1094 
       
  1095     QCryptographicHash hash(QCryptographicHash::Md5);
       
  1096     QByteArray hMsg;
       
  1097 
       
  1098     QByteArray iKeyPad(blockSize, 0x36);
       
  1099     QByteArray oKeyPad(blockSize, 0x5c);
       
  1100 
       
  1101     hash.reset();
       
  1102     // Adjust the key length to blockSize
       
  1103 
       
  1104     if(blockSize < key.length()) {
       
  1105         hash.addData(key);
       
  1106         key = hash.result(); //MD5 will always return 16 bytes length output
       
  1107     }
       
  1108 
       
  1109     //Key will be <= 16 or 20 bytes as hash function (MD5 or SHA hash algorithms)
       
  1110     //key size can be max of Block size only
       
  1111     key = key.leftJustified(blockSize,0,true);
       
  1112 
       
  1113     //iKeyPad, oKeyPad and key are all of same size "blockSize"
       
  1114 
       
  1115     //xor of iKeyPad with Key and store the result into iKeyPad
       
  1116     for(int i = 0; i<key.size();i++) {
       
  1117         iKeyPad[i] = key[i]^iKeyPad[i];
       
  1118     }
       
  1119 
       
  1120     //xor of oKeyPad with Key and store the result into oKeyPad
       
  1121     for(int i = 0; i<key.size();i++) {
       
  1122         oKeyPad[i] = key[i]^oKeyPad[i];
       
  1123     }
       
  1124 
       
  1125     iKeyPad.append(message); // (K0 xor ipad) || text
       
  1126 
       
  1127     hash.reset();
       
  1128     hash.addData(iKeyPad);
       
  1129     hMsg = hash.result();
       
  1130                     //Digest gen after pass-1: H((K0 xor ipad)||text)
       
  1131 
       
  1132     QByteArray hmacDigest;
       
  1133     oKeyPad.append(hMsg);
       
  1134     hash.reset();
       
  1135     hash.addData(oKeyPad);
       
  1136     hmacDigest = hash.result();
       
  1137                     // H((K0 xor opad )|| H((K0 xor ipad) || text))
       
  1138 
       
  1139     /*hmacDigest should not be less than half the length of the HMAC output
       
  1140       (to match the birthday attack bound) and not less than 80 bits
       
  1141       (a suitable lower bound on the number of bits that need to be
       
  1142       predicted by an attacker).
       
  1143       Refer RFC 2104 for more details on truncation part */
       
  1144 
       
  1145     /*MD5 hash always returns 16 byte digest only and HMAC-MD5 spec
       
  1146       (RFC 2104) also says digest length should be 16 bytes*/
       
  1147     return hmacDigest;
       
  1148 }
       
  1149 
       
  1150 static QByteArray qCreatev2Hash(const QAuthenticatorPrivate *ctx,
       
  1151                                 QNtlmPhase3Block *phase3)
       
  1152 {
       
  1153     Q_ASSERT(phase3 != 0);
       
  1154     // since v2 Hash is need for both NTLMv2 and LMv2 it is calculated
       
  1155     // only once and stored and reused
       
  1156     if(phase3->v2Hash.size() == 0) {
       
  1157         QCryptographicHash md4(QCryptographicHash::Md4);
       
  1158         QByteArray passUnicode = qStringAsUcs2Le(ctx->password);
       
  1159         md4.addData(passUnicode.data(), passUnicode.size());
       
  1160 
       
  1161         QByteArray hashKey = md4.result();
       
  1162         Q_ASSERT(hashKey.size() == 16);
       
  1163         // Assuming the user and domain is always unicode in challenge
       
  1164         QByteArray message =
       
  1165                 qStringAsUcs2Le(ctx->user.toUpper()) +
       
  1166                 qStringAsUcs2Le(ctx->realm);
       
  1167 
       
  1168         phase3->v2Hash = qEncodeHmacMd5(hashKey, message);
       
  1169     }
       
  1170     return phase3->v2Hash;
       
  1171 }
       
  1172 
       
  1173 static QByteArray clientChallenge(const QAuthenticatorPrivate *ctx)
       
  1174 {
       
  1175     Q_ASSERT(ctx->cnonce.size() >= 8);
       
  1176     QByteArray clientCh = ctx->cnonce.right(8);
       
  1177     return clientCh;
       
  1178 }
       
  1179 
       
  1180 // caller has to ensure a valid targetInfoBuff
       
  1181 static bool qExtractServerTime(const QByteArray& targetInfoBuff,
       
  1182                                quint64 *serverTime)
       
  1183 {
       
  1184     Q_ASSERT(serverTime != 0);
       
  1185     bool retValue = false;
       
  1186     QDataStream ds(targetInfoBuff);
       
  1187     ds.setByteOrder(QDataStream::LittleEndian);
       
  1188 
       
  1189     quint16 avId;
       
  1190     quint16 avLen;
       
  1191 
       
  1192     ds >> avId;
       
  1193     ds >> avLen;
       
  1194     while(avId != 0) {
       
  1195         if(avId == AVTIMESTAMP) {
       
  1196             QByteArray timeArray(avLen, 0);
       
  1197             //avLen size of QByteArray is allocated
       
  1198             ds.readRawData(timeArray.data(), avLen);
       
  1199             bool ok;
       
  1200             *serverTime = timeArray.toHex().toLongLong(&ok, 16);
       
  1201             retValue = true;
       
  1202             break;
       
  1203         }
       
  1204         ds.skipRawData(avLen);
       
  1205         ds >> avId;
       
  1206         ds >> avLen;
       
  1207     }
       
  1208     return retValue;
       
  1209 }
       
  1210 
       
  1211 static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx,
       
  1212                                         const QNtlmPhase2Block& ch,
       
  1213                                         QNtlmPhase3Block *phase3)
       
  1214 {
       
  1215     Q_ASSERT(phase3 != 0);
       
  1216     // return value stored in phase3
       
  1217     qCreatev2Hash(ctx, phase3);
       
  1218 
       
  1219     QByteArray temp;
       
  1220     QDataStream ds(&temp, QIODevice::WriteOnly);
       
  1221     ds.setByteOrder(QDataStream::LittleEndian);
       
  1222 
       
  1223     ds << respversion;
       
  1224     ds << hirespversion;
       
  1225 
       
  1226     //Reserved
       
  1227     QByteArray reserved1(6, 0);
       
  1228     ds.writeRawData(reserved1.constData(), reserved1.size());
       
  1229 
       
  1230     quint64 time = 0;
       
  1231 
       
  1232     //if server sends time, use it instead of current time
       
  1233     if(!(ch.targetInfo.len && qExtractServerTime(ch.targetInfoBuff, &time))) {
       
  1234         QDateTime currentTime(QDate::currentDate(),
       
  1235                               QTime::currentTime(), Qt::UTC);
       
  1236 
       
  1237         // number of seconds between 1601 and epoc(1970)
       
  1238         // 369 years, 89 leap years
       
  1239         // ((369 * 365) + 89) * 24 * 3600 = 11644473600
       
  1240 
       
  1241         time = Q_UINT64_C(currentTime.toTime_t() + 11644473600);
       
  1242 
       
  1243         // represented as 100 nano seconds
       
  1244         time = Q_UINT64_C(time * 10000000);
       
  1245     }
       
  1246     ds << time;
       
  1247 
       
  1248     //8 byte client challenge
       
  1249     QByteArray clientCh = clientChallenge(ctx);
       
  1250     ds.writeRawData(clientCh.constData(), clientCh.size());
       
  1251 
       
  1252     //Reserved
       
  1253     QByteArray reserved2(4, 0);
       
  1254     ds.writeRawData(reserved2.constData(), reserved2.size());
       
  1255 
       
  1256     if (ch.targetInfo.len > 0) {
       
  1257         ds.writeRawData(ch.targetInfoBuff.constData(),
       
  1258                         ch.targetInfoBuff.size());
       
  1259     }
       
  1260 
       
  1261     //Reserved
       
  1262     QByteArray reserved3(4, 0);
       
  1263     ds.writeRawData(reserved3.constData(), reserved3.size());
       
  1264 
       
  1265     QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
       
  1266     message.append(temp);
       
  1267 
       
  1268     QByteArray ntChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
       
  1269     ntChallengeResp.append(temp);
       
  1270 
       
  1271     return ntChallengeResp;
       
  1272 }
       
  1273 
       
  1274 static QByteArray qEncodeLmv2Response(const QAuthenticatorPrivate *ctx,
       
  1275                                       const QNtlmPhase2Block& ch,
       
  1276                                       QNtlmPhase3Block *phase3)
       
  1277 {
       
  1278     Q_ASSERT(phase3 != 0);
       
  1279     // return value stored in phase3
       
  1280     qCreatev2Hash(ctx, phase3);
       
  1281 
       
  1282     QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
       
  1283     QByteArray clientCh = clientChallenge(ctx);
       
  1284 
       
  1285     message.append(clientCh);
       
  1286 
       
  1287     QByteArray lmChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
       
  1288     lmChallengeResp.append(clientCh);
       
  1289 
       
  1290     return lmChallengeResp;
       
  1291 }
   945 
  1292 
   946 static bool qNtlmDecodePhase2(const QByteArray& data, QNtlmPhase2Block& ch)
  1293 static bool qNtlmDecodePhase2(const QByteArray& data, QNtlmPhase2Block& ch)
   947 {
  1294 {
   948     Q_ASSERT(QNtlmPhase2BlockBase::Size == sizeof(QNtlmPhase2BlockBase));
  1295     Q_ASSERT(QNtlmPhase2BlockBase::Size == sizeof(QNtlmPhase2BlockBase));
   949     if (data.size() < QNtlmPhase2BlockBase::Size)
  1296     if (data.size() < QNtlmPhase2BlockBase::Size)
   974 
  1321 
   975         ch.targetNameStr = qStringFromUcs2Le(data.mid(ch.targetName.offset, ch.targetName.len));
  1322         ch.targetNameStr = qStringFromUcs2Le(data.mid(ch.targetName.offset, ch.targetName.len));
   976     }
  1323     }
   977 
  1324 
   978     if (ch.targetInfo.len > 0) {
  1325     if (ch.targetInfo.len > 0) {
   979         // UNUSED right now
  1326         if (ch.targetInfo.len + ch.targetInfo.offset > (unsigned)data.size())
       
  1327             return false;
       
  1328 
       
  1329         ch.targetInfoBuff = data.mid(ch.targetInfo.offset, ch.targetInfo.len);
   980     }
  1330     }
   981 
  1331 
   982     return true;
  1332     return true;
   983 }
  1333 }
   984 
  1334 
   994     ds.setByteOrder(QDataStream::LittleEndian);
  1344     ds.setByteOrder(QDataStream::LittleEndian);
   995     QNtlmPhase3Block pb;
  1345     QNtlmPhase3Block pb;
   996 
  1346 
   997     bool unicode = ch.flags & NTLMSSP_NEGOTIATE_UNICODE;
  1347     bool unicode = ch.flags & NTLMSSP_NEGOTIATE_UNICODE;
   998 
  1348 
   999     ctx->realm = ch.targetNameStr;
  1349     if(ctx->realm.isEmpty())
       
  1350         ctx->realm = ch.targetNameStr;
  1000 
  1351 
  1001     pb.flags = NTLMSSP_NEGOTIATE_NTLM;
  1352     pb.flags = NTLMSSP_NEGOTIATE_NTLM;
  1002     if (unicode)
  1353     if (unicode)
  1003         pb.flags |= NTLMSSP_NEGOTIATE_UNICODE;
  1354         pb.flags |= NTLMSSP_NEGOTIATE_UNICODE;
  1004     else
  1355     else
  1008     int offset = QNtlmPhase3BlockBase::Size;
  1359     int offset = QNtlmPhase3BlockBase::Size;
  1009     Q_ASSERT(QNtlmPhase3BlockBase::Size == sizeof(QNtlmPhase3BlockBase));
  1360     Q_ASSERT(QNtlmPhase3BlockBase::Size == sizeof(QNtlmPhase3BlockBase));
  1010     
  1361     
  1011     offset = qEncodeNtlmString(pb.domain, offset, ctx->realm, unicode);
  1362     offset = qEncodeNtlmString(pb.domain, offset, ctx->realm, unicode);
  1012     pb.domainStr = ctx->realm;
  1363     pb.domainStr = ctx->realm;
       
  1364 
  1013     offset = qEncodeNtlmString(pb.user, offset, ctx->user, unicode);
  1365     offset = qEncodeNtlmString(pb.user, offset, ctx->user, unicode);
  1014     pb.userStr = ctx->user;
  1366     pb.userStr = ctx->user;
  1015 
  1367 
  1016     offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode);
  1368     offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode);
  1017     pb.workstationStr = ctx->workstation;
  1369     pb.workstationStr = ctx->workstation;
  1018 
  1370 
  1019     // Get LM response
  1371     // Get LM response
       
  1372 #ifdef NTLMV1_CLIENT
  1020     pb.lmResponseBuf = qEncodeLmResponse(ctx, ch);
  1373     pb.lmResponseBuf = qEncodeLmResponse(ctx, ch);
       
  1374 #else
       
  1375     if (ch.targetInfo.len > 0) {
       
  1376         pb.lmResponseBuf = QByteArray();
       
  1377     } else {
       
  1378         pb.lmResponseBuf = qEncodeLmv2Response(ctx, ch, &pb);
       
  1379     }
       
  1380 #endif
  1021     offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf);
  1381     offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf);
  1022 
  1382 
  1023     // Get NTLM response
  1383     // Get NTLM response
       
  1384 #ifdef NTLMV1_CLIENT
  1024     pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch);
  1385     pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch);
       
  1386 #else
       
  1387     pb.ntlmResponseBuf = qEncodeNtlmv2Response(ctx, ch, &pb);
       
  1388 #endif
  1025     offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf);
  1389     offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf);
  1026 
  1390 
  1027 
  1391 
  1028     // Encode and send
  1392     // Encode and send
  1029     ds << pb;
  1393     ds << pb;