Line | Source Code | Coverage |
---|
1 | /**************************************************************************** | - |
2 | ** | - |
3 | ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). | - |
4 | ** Contact: http://www.qt-project.org/legal | - |
5 | ** | - |
6 | ** This file is part of the QtNetwork module of the Qt Toolkit. | - |
7 | ** | - |
8 | ** $QT_BEGIN_LICENSE:LGPL$ | - |
9 | ** Commercial License Usage | - |
10 | ** Licensees holding valid commercial Qt licenses may use this file in | - |
11 | ** accordance with the commercial license agreement provided with the | - |
12 | ** Software or, alternatively, in accordance with the terms contained in | - |
13 | ** a written agreement between you and Digia. For licensing terms and | - |
14 | ** conditions see http://qt.digia.com/licensing. For further information | - |
15 | ** use the contact form at http://qt.digia.com/contact-us. | - |
16 | ** | - |
17 | ** GNU Lesser General Public License Usage | - |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - |
19 | ** General Public License version 2.1 as published by the Free Software | - |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the | - |
21 | ** packaging of this file. Please review the following information to | - |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements | - |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | - |
24 | ** | - |
25 | ** In addition, as a special exception, Digia gives you certain additional | - |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception | - |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | - |
28 | ** | - |
29 | ** GNU General Public License Usage | - |
30 | ** Alternatively, this file may be used under the terms of the GNU | - |
31 | ** General Public License version 3.0 as published by the Free Software | - |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the | - |
33 | ** packaging of this file. Please review the following information to | - |
34 | ** ensure the GNU General Public License version 3.0 requirements will be | - |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. | - |
36 | ** | - |
37 | ** | - |
38 | ** $QT_END_LICENSE$ | - |
39 | ** | - |
40 | ****************************************************************************/ | - |
41 | | - |
42 | #include <qauthenticator.h> | - |
43 | #include <qauthenticator_p.h> | - |
44 | #include <qdebug.h> | - |
45 | #include <qhash.h> | - |
46 | #include <qbytearray.h> | - |
47 | #include <qcryptographichash.h> | - |
48 | #include <qiodevice.h> | - |
49 | #include <qdatastream.h> | - |
50 | #include <qendian.h> | - |
51 | #include <qstring.h> | - |
52 | #include <qdatetime.h> | - |
53 | | - |
54 | #ifdef Q_OS_WIN | - |
55 | #include <qmutex.h> | - |
56 | #include <private/qmutexpool_p.h> | - |
57 | #include <rpc.h> | - |
58 | #define SECURITY_WIN32 1 | - |
59 | #include <security.h> | - |
60 | #endif | - |
61 | | - |
62 | //#define NTLMV1_CLIENT | - |
63 | | - |
64 | QT_BEGIN_NAMESPACE | - |
65 | | - |
66 | #ifdef NTLMV1_CLIENT | - |
67 | #include "../../3rdparty/des/des.cpp" | - |
68 | #endif | - |
69 | | - |
70 | static QByteArray qNtlmPhase1(); | - |
71 | static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data); | - |
72 | #ifdef Q_OS_WIN | - |
73 | static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx); | - |
74 | static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data); | - |
75 | #endif | - |
76 | | - |
77 | /*! | - |
78 | \class QAuthenticator | - |
79 | \brief The QAuthenticator class provides an authentication object. | - |
80 | \since 4.3 | - |
81 | | - |
82 | \reentrant | - |
83 | \ingroup network | - |
84 | \inmodule QtNetwork | - |
85 | | - |
86 | The QAuthenticator class is usually used in the | - |
87 | \l{QNetworkAccessManager::}{authenticationRequired()} and | - |
88 | \l{QNetworkAccessManager::}{proxyAuthenticationRequired()} signals of QNetworkAccessManager and | - |
89 | QAbstractSocket. The class provides a way to pass back the required | - |
90 | authentication information to the socket when accessing services that | - |
91 | require authentication. | - |
92 | | - |
93 | QAuthenticator supports the following authentication methods: | - |
94 | \list | - |
95 | \li Basic | - |
96 | \li NTLM version 2 | - |
97 | \li Digest-MD5 | - |
98 | \endlist | - |
99 | | - |
100 | \section1 Options | - |
101 | | - |
102 | In addition to the username and password required for authentication, a | - |
103 | QAuthenticator object can also contain additional options. The | - |
104 | options() function can be used to query incoming options sent by | - |
105 | the server; the setOption() function can | - |
106 | be used to set outgoing options, to be processed by the authenticator | - |
107 | calculation. The options accepted and provided depend on the authentication | - |
108 | type (see method()). | - |
109 | | - |
110 | The following tables list known incoming options as well as accepted | - |
111 | outgoing options. The list of incoming options is not exhaustive, since | - |
112 | servers may include additional information at any time. The list of | - |
113 | outgoing options is exhaustive, however, and no unknown options will be | - |
114 | treated or sent back to the server. | - |
115 | | - |
116 | \section2 Basic | - |
117 | | - |
118 | \table | - |
119 | \header \li Option \li Direction \li Description | - |
120 | \row \li \tt{realm} \li Incoming \li Contains the realm of the authentication, the same as realm() | - |
121 | \endtable | - |
122 | | - |
123 | The Basic authentication mechanism supports no outgoing options. | - |
124 | | - |
125 | \section2 NTLM version 2 | - |
126 | | - |
127 | The NTLM authentication mechanism currently supports no incoming or outgoing options. | - |
128 | On Windows, if no \a user has been set, domain\\user credentials will be searched for on the | - |
129 | local system to enable Single-Sign-On functionality. | - |
130 | | - |
131 | \section2 Digest-MD5 | - |
132 | | - |
133 | \table | - |
134 | \header \li Option \li Direction \li Description | - |
135 | \row \li \tt{realm} \li Incoming \li Contains the realm of the authentication, the same as realm() | - |
136 | \endtable | - |
137 | | - |
138 | The Digest-MD5 authentication mechanism supports no outgoing options. | - |
139 | | - |
140 | \sa QSslSocket | - |
141 | */ | - |
142 | | - |
143 | | - |
144 | /*! | - |
145 | Constructs an empty authentication object | - |
146 | */ | - |
147 | QAuthenticator::QAuthenticator() | - |
148 | : d(0) | - |
149 | { | - |
150 | } executed: } Execution Count:6158 | 6158 |
151 | | - |
152 | /*! | - |
153 | Destructs the object | - |
154 | */ | - |
155 | QAuthenticator::~QAuthenticator() | - |
156 | { | - |
157 | if (d) evaluated: d yes Evaluation Count:1698 | yes Evaluation Count:4460 |
| 1698-4460 |
158 | delete d; executed: delete d; Execution Count:1698 | 1698 |
159 | } executed: } Execution Count:6158 | 6158 |
160 | | - |
161 | /*! | - |
162 | Constructs a copy of \a other. | - |
163 | */ | - |
164 | QAuthenticator::QAuthenticator(const QAuthenticator &other) | - |
165 | : d(0) | - |
166 | { | - |
167 | if (other.d) | 0 |
168 | *this = other; never executed: *this = other; | 0 |
169 | } | 0 |
170 | | - |
171 | /*! | - |
172 | Assigns the contents of \a other to this authenticator. | - |
173 | */ | - |
174 | QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other) | - |
175 | { | - |
176 | if (d == other.d) partially evaluated: d == other.d no Evaluation Count:0 | yes Evaluation Count:33 |
| 0-33 |
177 | return *this; never executed: return *this; | 0 |
178 | | - |
179 | // Do not share the d since challange reponse/based changes | - |
180 | // could corrupt the internal store and different network requests | - |
181 | // can utilize different types of proxies. | - |
182 | detach(); executed (the execution status of this line is deduced): detach(); | - |
183 | if (other.d) { partially evaluated: other.d no Evaluation Count:0 | yes Evaluation Count:33 |
| 0-33 |
184 | d->user = other.d->user; never executed (the execution status of this line is deduced): d->user = other.d->user; | - |
185 | d->userDomain = other.d->userDomain; never executed (the execution status of this line is deduced): d->userDomain = other.d->userDomain; | - |
186 | d->workstation = other.d->workstation; never executed (the execution status of this line is deduced): d->workstation = other.d->workstation; | - |
187 | d->extractedUser = other.d->extractedUser; never executed (the execution status of this line is deduced): d->extractedUser = other.d->extractedUser; | - |
188 | d->password = other.d->password; never executed (the execution status of this line is deduced): d->password = other.d->password; | - |
189 | d->realm = other.d->realm; never executed (the execution status of this line is deduced): d->realm = other.d->realm; | - |
190 | d->method = other.d->method; never executed (the execution status of this line is deduced): d->method = other.d->method; | - |
191 | d->options = other.d->options; never executed (the execution status of this line is deduced): d->options = other.d->options; | - |
192 | } else { | 0 |
193 | delete d; executed (the execution status of this line is deduced): delete d; | - |
194 | d = 0; executed (the execution status of this line is deduced): d = 0; | - |
195 | } executed: } Execution Count:33 | 33 |
196 | return *this; executed: return *this; Execution Count:33 | 33 |
197 | } | - |
198 | | - |
199 | /*! | - |
200 | Returns true if this authenticator is identical to \a other; otherwise | - |
201 | returns false. | - |
202 | */ | - |
203 | bool QAuthenticator::operator==(const QAuthenticator &other) const | - |
204 | { | - |
205 | if (d == other.d) never evaluated: d == other.d | 0 |
206 | return true; never executed: return true; | 0 |
207 | return d->user == other.d->user never executed: return d->user == other.d->user && d->password == other.d->password && d->realm == other.d->realm && d->method == other.d->method && d->options == other.d->options; | 0 |
208 | && d->password == other.d->password never executed: return d->user == other.d->user && d->password == other.d->password && d->realm == other.d->realm && d->method == other.d->method && d->options == other.d->options; | 0 |
209 | && d->realm == other.d->realm never executed: return d->user == other.d->user && d->password == other.d->password && d->realm == other.d->realm && d->method == other.d->method && d->options == other.d->options; | 0 |
210 | && d->method == other.d->method never executed: return d->user == other.d->user && d->password == other.d->password && d->realm == other.d->realm && d->method == other.d->method && d->options == other.d->options; | 0 |
211 | && d->options == other.d->options; never executed: return d->user == other.d->user && d->password == other.d->password && d->realm == other.d->realm && d->method == other.d->method && d->options == other.d->options; | 0 |
212 | } | - |
213 | | - |
214 | /*! | - |
215 | \fn bool QAuthenticator::operator!=(const QAuthenticator &other) const | - |
216 | | - |
217 | Returns true if this authenticator is different from \a other; otherwise | - |
218 | returns false. | - |
219 | */ | - |
220 | | - |
221 | /*! | - |
222 | returns the user used for authentication. | - |
223 | */ | - |
224 | QString QAuthenticator::user() const | - |
225 | { | - |
226 | return d ? d->user : QString(); executed: return d ? d->user : QString(); Execution Count:3588 | 3588 |
227 | } | - |
228 | | - |
229 | /*! | - |
230 | Sets the \a user used for authentication. | - |
231 | | - |
232 | \sa QNetworkAccessManager::authenticationRequired() | - |
233 | */ | - |
234 | void QAuthenticator::setUser(const QString &user) | - |
235 | { | - |
236 | detach(); executed (the execution status of this line is deduced): detach(); | - |
237 | d->user = user; executed (the execution status of this line is deduced): d->user = user; | - |
238 | d->updateCredentials(); executed (the execution status of this line is deduced): d->updateCredentials(); | - |
239 | } executed: } Execution Count:879 | 879 |
240 | | - |
241 | /*! | - |
242 | returns the password used for authentication. | - |
243 | */ | - |
244 | QString QAuthenticator::password() const | - |
245 | { | - |
246 | return d ? d->password : QString(); executed: return d ? d->password : QString(); Execution Count:3295 | 3295 |
247 | } | - |
248 | | - |
249 | /*! | - |
250 | Sets the \a password used for authentication. | - |
251 | | - |
252 | \sa QNetworkAccessManager::authenticationRequired() | - |
253 | */ | - |
254 | void QAuthenticator::setPassword(const QString &password) | - |
255 | { | - |
256 | detach(); executed (the execution status of this line is deduced): detach(); | - |
257 | d->password = password; executed (the execution status of this line is deduced): d->password = password; | - |
258 | } executed: } Execution Count:889 | 889 |
259 | | - |
260 | /*! | - |
261 | \internal | - |
262 | */ | - |
263 | void QAuthenticator::detach() | - |
264 | { | - |
265 | if (!d) { evaluated: !d yes Evaluation Count:1731 | yes Evaluation Count:1451 |
| 1451-1731 |
266 | d = new QAuthenticatorPrivate; executed (the execution status of this line is deduced): d = new QAuthenticatorPrivate; | - |
267 | return; executed: return; Execution Count:1731 | 1731 |
268 | } | - |
269 | | - |
270 | d->phase = QAuthenticatorPrivate::Start; executed (the execution status of this line is deduced): d->phase = QAuthenticatorPrivate::Start; | - |
271 | } executed: } Execution Count:1451 | 1451 |
272 | | - |
273 | /*! | - |
274 | returns the realm requiring authentication. | - |
275 | */ | - |
276 | QString QAuthenticator::realm() const | - |
277 | { | - |
278 | return d ? d->realm : QString(); executed: return d ? d->realm : QString(); Execution Count:406 | 406 |
279 | } | - |
280 | | - |
281 | /*! | - |
282 | \since 4.7 | - |
283 | Returns the value related to option \a opt if it was set by the server. | - |
284 | See \l{QAuthenticator#Options} for more information on incoming options. | - |
285 | If option \a opt isn't found, an invalid QVariant will be returned. | - |
286 | | - |
287 | \sa options(), QAuthenticator#Options | - |
288 | */ | - |
289 | QVariant QAuthenticator::option(const QString &opt) const | - |
290 | { | - |
291 | return d ? d->options.value(opt) : QVariant(); never executed: return d ? d->options.value(opt) : QVariant(); | 0 |
292 | } | - |
293 | | - |
294 | /*! | - |
295 | \since 4.7 | - |
296 | Returns all incoming options set in this QAuthenticator object by parsing | - |
297 | the server reply. See \l{QAuthenticator#Options} for more information | - |
298 | on incoming options. | - |
299 | | - |
300 | \sa option(), QAuthenticator#Options | - |
301 | */ | - |
302 | QVariantHash QAuthenticator::options() const | - |
303 | { | - |
304 | return d ? d->options : QVariantHash(); never executed: return d ? d->options : QVariantHash(); | 0 |
305 | } | - |
306 | | - |
307 | /*! | - |
308 | \since 4.7 | - |
309 | | - |
310 | Sets the outgoing option \a opt to value \a value. | - |
311 | See \l{QAuthenticator#Options} for more information on outgoing options. | - |
312 | | - |
313 | \sa options(), option(), QAuthenticator#Options | - |
314 | */ | - |
315 | void QAuthenticator::setOption(const QString &opt, const QVariant &value) | - |
316 | { | - |
317 | detach(); never executed (the execution status of this line is deduced): detach(); | - |
318 | d->options.insert(opt, value); never executed (the execution status of this line is deduced): d->options.insert(opt, value); | - |
319 | } | 0 |
320 | | - |
321 | | - |
322 | /*! | - |
323 | Returns true if the authenticator is null. | - |
324 | */ | - |
325 | bool QAuthenticator::isNull() const | - |
326 | { | - |
327 | return !d; executed: return !d; Execution Count:349 | 349 |
328 | } | - |
329 | | - |
330 | #ifdef Q_OS_WIN | - |
331 | class QNtlmWindowsHandles | - |
332 | { | - |
333 | public: | - |
334 | CredHandle credHandle; | - |
335 | CtxtHandle ctxHandle; | - |
336 | }; | - |
337 | #endif | - |
338 | | - |
339 | | - |
340 | QAuthenticatorPrivate::QAuthenticatorPrivate() | - |
341 | : method(None) | - |
342 | #ifdef Q_OS_WIN | - |
343 | , ntlmWindowsHandles(0) | - |
344 | #endif | - |
345 | , hasFailed(false) | - |
346 | , phase(Start) | - |
347 | , nonceCount(0) | - |
348 | { | - |
349 | cnonce = QCryptographicHash::hash(QByteArray::number(qrand(), 16) + QByteArray::number(qrand(), 16), executed (the execution status of this line is deduced): cnonce = QCryptographicHash::hash(QByteArray::number(qrand(), 16) + QByteArray::number(qrand(), 16), | - |
350 | QCryptographicHash::Md5).toHex(); executed (the execution status of this line is deduced): QCryptographicHash::Md5).toHex(); | - |
351 | nonceCount = 0; executed (the execution status of this line is deduced): nonceCount = 0; | - |
352 | } executed: } Execution Count:1731 | 1731 |
353 | | - |
354 | QAuthenticatorPrivate::~QAuthenticatorPrivate() | - |
355 | { | - |
356 | #ifdef Q_OS_WIN | - |
357 | if (ntlmWindowsHandles) | - |
358 | delete ntlmWindowsHandles; | - |
359 | #endif | - |
360 | } | - |
361 | | - |
362 | void QAuthenticatorPrivate::updateCredentials() | - |
363 | { | - |
364 | int separatorPosn = 0; executed (the execution status of this line is deduced): int separatorPosn = 0; | - |
365 | | - |
366 | switch (method) { | - |
367 | case QAuthenticatorPrivate::Ntlm: | - |
368 | if ((separatorPosn = user.indexOf(QLatin1String("\\"))) != -1) { never evaluated: (separatorPosn = user.indexOf(QLatin1String("\\"))) != -1 | 0 |
369 | //domain name is present | - |
370 | realm.clear(); never executed (the execution status of this line is deduced): realm.clear(); | - |
371 | userDomain = user.left(separatorPosn); never executed (the execution status of this line is deduced): userDomain = user.left(separatorPosn); | - |
372 | extractedUser = user.mid(separatorPosn + 1); never executed (the execution status of this line is deduced): extractedUser = user.mid(separatorPosn + 1); | - |
373 | } else { | 0 |
374 | extractedUser = user; never executed (the execution status of this line is deduced): extractedUser = user; | - |
375 | realm.clear(); never executed (the execution status of this line is deduced): realm.clear(); | - |
376 | userDomain.clear(); never executed (the execution status of this line is deduced): userDomain.clear(); | - |
377 | } | 0 |
378 | break; | 0 |
379 | default: | - |
380 | userDomain.clear(); executed (the execution status of this line is deduced): userDomain.clear(); | - |
381 | break; executed: break; Execution Count:1221 | 1221 |
382 | } | - |
383 | } executed: } Execution Count:1221 | 1221 |
384 | | - |
385 | void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy) | - |
386 | { | - |
387 | const char *search = isProxy ? "proxy-authenticate" : "www-authenticate"; evaluated: isProxy yes Evaluation Count:67 | yes Evaluation Count:275 |
| 67-275 |
388 | | - |
389 | method = None; executed (the execution status of this line is deduced): method = None; | - |
390 | /* | - |
391 | Fun from the HTTP 1.1 specs, that we currently ignore: | - |
392 | | - |
393 | User agents are advised to take special care in parsing the WWW- | - |
394 | Authenticate field value as it might contain more than one challenge, | - |
395 | or if more than one WWW-Authenticate header field is provided, the | - |
396 | contents of a challenge itself can contain a comma-separated list of | - |
397 | authentication parameters. | - |
398 | */ | - |
399 | | - |
400 | QByteArray headerVal; executed (the execution status of this line is deduced): QByteArray headerVal; | - |
401 | for (int i = 0; i < values.size(); ++i) { evaluated: i < values.size() yes Evaluation Count:2727 | yes Evaluation Count:342 |
| 342-2727 |
402 | const QPair<QByteArray, QByteArray> ¤t = values.at(i); executed (the execution status of this line is deduced): const QPair<QByteArray, QByteArray> ¤t = values.at(i); | - |
403 | if (current.first.toLower() != search) evaluated: current.first.toLower() != search yes Evaluation Count:2385 | yes Evaluation Count:342 |
| 342-2385 |
404 | continue; executed: continue; Execution Count:2385 | 2385 |
405 | QByteArray str = current.second.toLower(); executed (the execution status of this line is deduced): QByteArray str = current.second.toLower(); | - |
406 | if (method < Basic && str.startsWith("basic")) { partially evaluated: method < Basic yes Evaluation Count:342 | no Evaluation Count:0 |
evaluated: str.startsWith("basic") yes Evaluation Count:280 | yes Evaluation Count:62 |
| 0-342 |
407 | method = Basic; executed (the execution status of this line is deduced): method = Basic; | - |
408 | headerVal = current.second.mid(6); executed (the execution status of this line is deduced): headerVal = current.second.mid(6); | - |
409 | } else if (method < Ntlm && str.startsWith("ntlm")) { executed: } Execution Count:280 partially evaluated: method < Ntlm yes Evaluation Count:62 | no Evaluation Count:0 |
partially evaluated: str.startsWith("ntlm") no Evaluation Count:0 | yes Evaluation Count:62 |
| 0-280 |
410 | method = Ntlm; never executed (the execution status of this line is deduced): method = Ntlm; | - |
411 | headerVal = current.second.mid(5); never executed (the execution status of this line is deduced): headerVal = current.second.mid(5); | - |
412 | } else if (method < DigestMd5 && str.startsWith("digest")) { never executed: } partially evaluated: method < DigestMd5 yes Evaluation Count:62 | no Evaluation Count:0 |
partially evaluated: str.startsWith("digest") yes Evaluation Count:62 | no Evaluation Count:0 |
| 0-62 |
413 | method = DigestMd5; executed (the execution status of this line is deduced): method = DigestMd5; | - |
414 | headerVal = current.second.mid(7); executed (the execution status of this line is deduced): headerVal = current.second.mid(7); | - |
415 | } executed: } Execution Count:62 | 62 |
416 | } | - |
417 | | - |
418 | // Reparse credentials since we know the method now | - |
419 | updateCredentials(); executed (the execution status of this line is deduced): updateCredentials(); | - |
420 | challenge = headerVal.trimmed(); executed (the execution status of this line is deduced): challenge = headerVal.trimmed(); | - |
421 | QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge); executed (the execution status of this line is deduced): QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge); | - |
422 | | - |
423 | switch(method) { | - |
424 | case Basic: | - |
425 | this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); executed (the execution status of this line is deduced): this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); | - |
426 | if (user.isEmpty() && password.isEmpty()) evaluated: user.isEmpty() yes Evaluation Count:119 | yes Evaluation Count:161 |
partially evaluated: password.isEmpty() yes Evaluation Count:119 | no Evaluation Count:0 |
| 0-161 |
427 | phase = Done; executed: phase = Done; Execution Count:119 | 119 |
428 | break; executed: break; Execution Count:280 | 280 |
429 | case Ntlm: | - |
430 | // #### extract from header | - |
431 | if (user.isEmpty() && password.isEmpty()) never evaluated: user.isEmpty() never evaluated: password.isEmpty() | 0 |
432 | phase = Done; never executed: phase = Done; | 0 |
433 | break; | 0 |
434 | case DigestMd5: { | - |
435 | this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); executed (the execution status of this line is deduced): this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); | - |
436 | if (options.value("stale").toLower() == "true") partially evaluated: options.value("stale").toLower() == "true" no Evaluation Count:0 | yes Evaluation Count:62 |
| 0-62 |
437 | phase = Start; never executed: phase = Start; | 0 |
438 | if (user.isEmpty() && password.isEmpty()) evaluated: user.isEmpty() yes Evaluation Count:6 | yes Evaluation Count:56 |
partially evaluated: password.isEmpty() yes Evaluation Count:6 | no Evaluation Count:0 |
| 0-56 |
439 | phase = Done; executed: phase = Done; Execution Count:6 | 6 |
440 | break; executed: break; Execution Count:62 | 62 |
441 | } | - |
442 | default: | - |
443 | realm.clear(); never executed (the execution status of this line is deduced): realm.clear(); | - |
444 | challenge = QByteArray(); never executed (the execution status of this line is deduced): challenge = QByteArray(); | - |
445 | phase = Invalid; never executed (the execution status of this line is deduced): phase = Invalid; | - |
446 | } | 0 |
447 | } executed: } Execution Count:342 | 342 |
448 | | - |
449 | QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path) | - |
450 | { | - |
451 | QByteArray response; executed (the execution status of this line is deduced): QByteArray response; | - |
452 | const char *methodString = 0; executed (the execution status of this line is deduced): const char *methodString = 0; | - |
453 | switch(method) { | - |
454 | case QAuthenticatorPrivate::None: | - |
455 | methodString = ""; never executed (the execution status of this line is deduced): methodString = ""; | - |
456 | phase = Done; never executed (the execution status of this line is deduced): phase = Done; | - |
457 | break; | 0 |
458 | case QAuthenticatorPrivate::Plain: | - |
459 | response = '\0' + user.toUtf8() + '\0' + password.toUtf8(); never executed (the execution status of this line is deduced): response = '\0' + user.toUtf8() + '\0' + password.toUtf8(); | - |
460 | phase = Done; never executed (the execution status of this line is deduced): phase = Done; | - |
461 | break; | 0 |
462 | case QAuthenticatorPrivate::Basic: | - |
463 | methodString = "Basic "; executed (the execution status of this line is deduced): methodString = "Basic "; | - |
464 | response = user.toLatin1() + ':' + password.toLatin1(); executed (the execution status of this line is deduced): response = user.toLatin1() + ':' + password.toLatin1(); | - |
465 | response = response.toBase64(); executed (the execution status of this line is deduced): response = response.toBase64(); | - |
466 | phase = Done; executed (the execution status of this line is deduced): phase = Done; | - |
467 | break; executed: break; Execution Count:157 | 157 |
468 | case QAuthenticatorPrivate::Login: | - |
469 | if (challenge.contains("VXNlciBOYW1lAA==")) { never evaluated: challenge.contains("VXNlciBOYW1lAA==") | 0 |
470 | response = user.toUtf8().toBase64(); never executed (the execution status of this line is deduced): response = user.toUtf8().toBase64(); | - |
471 | phase = Phase2; never executed (the execution status of this line is deduced): phase = Phase2; | - |
472 | } else if (challenge.contains("UGFzc3dvcmQA")) { never executed: } never evaluated: challenge.contains("UGFzc3dvcmQA") | 0 |
473 | response = password.toUtf8().toBase64(); never executed (the execution status of this line is deduced): response = password.toUtf8().toBase64(); | - |
474 | phase = Done; never executed (the execution status of this line is deduced): phase = Done; | - |
475 | } | 0 |
476 | break; | 0 |
477 | case QAuthenticatorPrivate::CramMd5: | - |
478 | break; | 0 |
479 | case QAuthenticatorPrivate::DigestMd5: | - |
480 | methodString = "Digest "; executed (the execution status of this line is deduced): methodString = "Digest "; | - |
481 | response = digestMd5Response(challenge, requestMethod, path); executed (the execution status of this line is deduced): response = digestMd5Response(challenge, requestMethod, path); | - |
482 | phase = Done; executed (the execution status of this line is deduced): phase = Done; | - |
483 | break; executed: break; Execution Count:33 | 33 |
484 | case QAuthenticatorPrivate::Ntlm: | - |
485 | methodString = "NTLM "; never executed (the execution status of this line is deduced): methodString = "NTLM "; | - |
486 | if (challenge.isEmpty()) { never evaluated: challenge.isEmpty() | 0 |
487 | #ifdef Q_OS_WIN | - |
488 | QByteArray phase1Token; | - |
489 | if (user.isEmpty()) // Only pull from system if no user was specified in authenticator | - |
490 | phase1Token = qNtlmPhase1_SSPI(this); | - |
491 | if (!phase1Token.isEmpty()) { | - |
492 | response = phase1Token.toBase64(); | - |
493 | phase = Phase2; | - |
494 | } else | - |
495 | #endif | - |
496 | { | - |
497 | response = qNtlmPhase1().toBase64(); never executed (the execution status of this line is deduced): response = qNtlmPhase1().toBase64(); | - |
498 | if (user.isEmpty()) never evaluated: user.isEmpty() | 0 |
499 | phase = Done; never executed: phase = Done; | 0 |
500 | else | - |
501 | phase = Phase2; never executed: phase = Phase2; | 0 |
502 | } | - |
503 | } else { | - |
504 | #ifdef Q_OS_WIN | - |
505 | QByteArray phase3Token; | - |
506 | if (ntlmWindowsHandles) | - |
507 | phase3Token = qNtlmPhase3_SSPI(this, QByteArray::fromBase64(challenge)); | - |
508 | if (!phase3Token.isEmpty()) { | - |
509 | response = phase3Token.toBase64(); | - |
510 | phase = Done; | - |
511 | } else | - |
512 | #endif | - |
513 | { | - |
514 | response = qNtlmPhase3(this, QByteArray::fromBase64(challenge)).toBase64(); never executed (the execution status of this line is deduced): response = qNtlmPhase3(this, QByteArray::fromBase64(challenge)).toBase64(); | - |
515 | phase = Done; never executed (the execution status of this line is deduced): phase = Done; | - |
516 | } | - |
517 | } | 0 |
518 | | - |
519 | break; | 0 |
520 | } | - |
521 | return QByteArray(methodString) + response; executed: return QByteArray(methodString) + response; Execution Count:190 | 190 |
522 | } | - |
523 | | - |
524 | | - |
525 | // ---------------------------- Digest Md5 code ---------------------------------------- | - |
526 | | - |
527 | QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationChallenge(const QByteArray &challenge) | - |
528 | { | - |
529 | QHash<QByteArray, QByteArray> options; executed (the execution status of this line is deduced): QHash<QByteArray, QByteArray> options; | - |
530 | // parse the challenge | - |
531 | const char *d = challenge.constData(); executed (the execution status of this line is deduced): const char *d = challenge.constData(); | - |
532 | const char *end = d + challenge.length(); executed (the execution status of this line is deduced): const char *end = d + challenge.length(); | - |
533 | while (d < end) { evaluated: d < end yes Evaluation Count:660 | yes Evaluation Count:375 |
| 375-660 |
534 | while (d < end && (*d == ' ' || *d == '\n' || *d == '\r')) partially evaluated: d < end yes Evaluation Count:945 | no Evaluation Count:0 |
evaluated: *d == ' ' yes Evaluation Count:285 | yes Evaluation Count:660 |
partially evaluated: *d == '\n' no Evaluation Count:0 | yes Evaluation Count:660 |
partially evaluated: *d == '\r' no Evaluation Count:0 | yes Evaluation Count:660 |
| 0-945 |
535 | ++d; executed: ++d; Execution Count:285 | 285 |
536 | const char *start = d; executed (the execution status of this line is deduced): const char *start = d; | - |
537 | while (d < end && *d != '=') partially evaluated: d < end yes Evaluation Count:4150 | no Evaluation Count:0 |
evaluated: *d != '=' yes Evaluation Count:3490 | yes Evaluation Count:660 |
| 0-4150 |
538 | ++d; executed: ++d; Execution Count:3490 | 3490 |
539 | QByteArray key = QByteArray(start, d - start); executed (the execution status of this line is deduced): QByteArray key = QByteArray(start, d - start); | - |
540 | ++d; executed (the execution status of this line is deduced): ++d; | - |
541 | if (d >= end) partially evaluated: d >= end no Evaluation Count:0 | yes Evaluation Count:660 |
| 0-660 |
542 | break; | 0 |
543 | bool quote = (*d == '"'); executed (the execution status of this line is deduced): bool quote = (*d == '"'); | - |
544 | if (quote) evaluated: quote yes Evaluation Count:565 | yes Evaluation Count:95 |
| 95-565 |
545 | ++d; executed: ++d; Execution Count:565 | 565 |
546 | if (d >= end) partially evaluated: d >= end no Evaluation Count:0 | yes Evaluation Count:660 |
| 0-660 |
547 | break; | 0 |
548 | start = d; executed (the execution status of this line is deduced): start = d; | - |
549 | QByteArray value; executed (the execution status of this line is deduced): QByteArray value; | - |
550 | while (d < end) { partially evaluated: d < end yes Evaluation Count:13583 | no Evaluation Count:0 |
| 0-13583 |
551 | bool backslash = false; executed (the execution status of this line is deduced): bool backslash = false; | - |
552 | if (*d == '\\' && d < end - 1) { partially evaluated: *d == '\\' no Evaluation Count:0 | yes Evaluation Count:13583 |
never evaluated: d < end - 1 | 0-13583 |
553 | ++d; never executed (the execution status of this line is deduced): ++d; | - |
554 | backslash = true; never executed (the execution status of this line is deduced): backslash = true; | - |
555 | } | 0 |
556 | if (!backslash) { partially evaluated: !backslash yes Evaluation Count:13583 | no Evaluation Count:0 |
| 0-13583 |
557 | if (quote) { evaluated: quote yes Evaluation Count:13203 | yes Evaluation Count:380 |
| 380-13203 |
558 | if (*d == '"') evaluated: *d == '"' yes Evaluation Count:565 | yes Evaluation Count:12638 |
| 565-12638 |
559 | break; executed: break; Execution Count:565 | 565 |
560 | } else { executed: } Execution Count:12638 | 12638 |
561 | if (*d == ',') evaluated: *d == ',' yes Evaluation Count:95 | yes Evaluation Count:285 |
| 95-285 |
562 | break; executed: break; Execution Count:95 | 95 |
563 | } executed: } Execution Count:285 | 285 |
564 | } | - |
565 | value += *d; executed (the execution status of this line is deduced): value += *d; | - |
566 | ++d; executed (the execution status of this line is deduced): ++d; | - |
567 | } executed: } Execution Count:12923 | 12923 |
568 | while (d < end && *d != ',') evaluated: d < end yes Evaluation Count:850 | yes Evaluation Count:375 |
evaluated: *d != ',' yes Evaluation Count:565 | yes Evaluation Count:285 |
| 285-850 |
569 | ++d; executed: ++d; Execution Count:565 | 565 |
570 | ++d; executed (the execution status of this line is deduced): ++d; | - |
571 | options[key] = value; executed (the execution status of this line is deduced): options[key] = value; | - |
572 | } executed: } Execution Count:660 | 660 |
573 | | - |
574 | QByteArray qop = options.value("qop"); executed (the execution status of this line is deduced): QByteArray qop = options.value("qop"); | - |
575 | if (!qop.isEmpty()) { evaluated: !qop.isEmpty() yes Evaluation Count:95 | yes Evaluation Count:280 |
| 95-280 |
576 | QList<QByteArray> qopoptions = qop.split(','); executed (the execution status of this line is deduced): QList<QByteArray> qopoptions = qop.split(','); | - |
577 | if (!qopoptions.contains("auth")) partially evaluated: !qopoptions.contains("auth") no Evaluation Count:0 | yes Evaluation Count:95 |
| 0-95 |
578 | return QHash<QByteArray, QByteArray>(); never executed: return QHash<QByteArray, QByteArray>(); | 0 |
579 | // #### can't do auth-int currently | - |
580 | // if (qop.contains("auth-int")) | - |
581 | // qop = "auth-int"; | - |
582 | // else if (qop.contains("auth")) | - |
583 | // qop = "auth"; | - |
584 | // else | - |
585 | // qop = QByteArray(); | - |
586 | options["qop"] = "auth"; executed (the execution status of this line is deduced): options["qop"] = "auth"; | - |
587 | } executed: } Execution Count:95 | 95 |
588 | | - |
589 | return options; executed: return options; Execution Count:375 | 375 |
590 | } | - |
591 | | - |
592 | /* | - |
593 | Digest MD5 implementation | - |
594 | | - |
595 | Code taken from RFC 2617 | - |
596 | | - |
597 | Currently we don't support the full SASL authentication mechanism (which includes cyphers) | - |
598 | */ | - |
599 | | - |
600 | | - |
601 | /* calculate request-digest/response-digest as per HTTP Digest spec */ | - |
602 | static QByteArray digestMd5ResponseHelper( | - |
603 | const QByteArray &alg, | - |
604 | const QByteArray &userName, | - |
605 | const QByteArray &realm, | - |
606 | const QByteArray &password, | - |
607 | const QByteArray &nonce, /* nonce from server */ | - |
608 | const QByteArray &nonceCount, /* 8 hex digits */ | - |
609 | const QByteArray &cNonce, /* client nonce */ | - |
610 | const QByteArray &qop, /* qop-value: "", "auth", "auth-int" */ | - |
611 | const QByteArray &method, /* method from the request */ | - |
612 | const QByteArray &digestUri, /* requested URL */ | - |
613 | const QByteArray &hEntity /* H(entity body) if qop="auth-int" */ | - |
614 | ) | - |
615 | { | - |
616 | QCryptographicHash hash(QCryptographicHash::Md5); executed (the execution status of this line is deduced): QCryptographicHash hash(QCryptographicHash::Md5); | - |
617 | hash.addData(userName); executed (the execution status of this line is deduced): hash.addData(userName); | - |
618 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
619 | hash.addData(realm); executed (the execution status of this line is deduced): hash.addData(realm); | - |
620 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
621 | hash.addData(password); executed (the execution status of this line is deduced): hash.addData(password); | - |
622 | QByteArray ha1 = hash.result(); executed (the execution status of this line is deduced): QByteArray ha1 = hash.result(); | - |
623 | if (alg.toLower() == "md5-sess") { partially evaluated: alg.toLower() == "md5-sess" no Evaluation Count:0 | yes Evaluation Count:33 |
| 0-33 |
624 | hash.reset(); never executed (the execution status of this line is deduced): hash.reset(); | - |
625 | // RFC 2617 contains an error, it was: | - |
626 | // hash.addData(ha1); | - |
627 | // but according to the errata page at http://www.rfc-editor.org/errata_list.php, ID 1649, it | - |
628 | // must be the following line: | - |
629 | hash.addData(ha1.toHex()); never executed (the execution status of this line is deduced): hash.addData(ha1.toHex()); | - |
630 | hash.addData(":", 1); never executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
631 | hash.addData(nonce); never executed (the execution status of this line is deduced): hash.addData(nonce); | - |
632 | hash.addData(":", 1); never executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
633 | hash.addData(cNonce); never executed (the execution status of this line is deduced): hash.addData(cNonce); | - |
634 | ha1 = hash.result(); never executed (the execution status of this line is deduced): ha1 = hash.result(); | - |
635 | }; | 0 |
636 | ha1 = ha1.toHex(); executed (the execution status of this line is deduced): ha1 = ha1.toHex(); | - |
637 | | - |
638 | // calculate H(A2) | - |
639 | hash.reset(); executed (the execution status of this line is deduced): hash.reset(); | - |
640 | hash.addData(method); executed (the execution status of this line is deduced): hash.addData(method); | - |
641 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
642 | hash.addData(digestUri); executed (the execution status of this line is deduced): hash.addData(digestUri); | - |
643 | if (qop.toLower() == "auth-int") { partially evaluated: qop.toLower() == "auth-int" no Evaluation Count:0 | yes Evaluation Count:33 |
| 0-33 |
644 | hash.addData(":", 1); never executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
645 | hash.addData(hEntity); never executed (the execution status of this line is deduced): hash.addData(hEntity); | - |
646 | } | 0 |
647 | QByteArray ha2hex = hash.result().toHex(); executed (the execution status of this line is deduced): QByteArray ha2hex = hash.result().toHex(); | - |
648 | | - |
649 | // calculate response | - |
650 | hash.reset(); executed (the execution status of this line is deduced): hash.reset(); | - |
651 | hash.addData(ha1); executed (the execution status of this line is deduced): hash.addData(ha1); | - |
652 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
653 | hash.addData(nonce); executed (the execution status of this line is deduced): hash.addData(nonce); | - |
654 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
655 | if (!qop.isNull()) { partially evaluated: !qop.isNull() yes Evaluation Count:33 | no Evaluation Count:0 |
| 0-33 |
656 | hash.addData(nonceCount); executed (the execution status of this line is deduced): hash.addData(nonceCount); | - |
657 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
658 | hash.addData(cNonce); executed (the execution status of this line is deduced): hash.addData(cNonce); | - |
659 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
660 | hash.addData(qop); executed (the execution status of this line is deduced): hash.addData(qop); | - |
661 | hash.addData(":", 1); executed (the execution status of this line is deduced): hash.addData(":", 1); | - |
662 | } executed: } Execution Count:33 | 33 |
663 | hash.addData(ha2hex); executed (the execution status of this line is deduced): hash.addData(ha2hex); | - |
664 | return hash.result().toHex(); executed: return hash.result().toHex(); Execution Count:33 | 33 |
665 | } | - |
666 | | - |
667 | QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path) | - |
668 | { | - |
669 | QHash<QByteArray,QByteArray> options = parseDigestAuthenticationChallenge(challenge); executed (the execution status of this line is deduced): QHash<QByteArray,QByteArray> options = parseDigestAuthenticationChallenge(challenge); | - |
670 | | - |
671 | ++nonceCount; executed (the execution status of this line is deduced): ++nonceCount; | - |
672 | QByteArray nonceCountString = QByteArray::number(nonceCount, 16); executed (the execution status of this line is deduced): QByteArray nonceCountString = QByteArray::number(nonceCount, 16); | - |
673 | while (nonceCountString.length() < 8) evaluated: nonceCountString.length() < 8 yes Evaluation Count:231 | yes Evaluation Count:33 |
| 33-231 |
674 | nonceCountString.prepend('0'); executed: nonceCountString.prepend('0'); Execution Count:231 | 231 |
675 | | - |
676 | QByteArray nonce = options.value("nonce"); executed (the execution status of this line is deduced): QByteArray nonce = options.value("nonce"); | - |
677 | QByteArray opaque = options.value("opaque"); executed (the execution status of this line is deduced): QByteArray opaque = options.value("opaque"); | - |
678 | QByteArray qop = options.value("qop"); executed (the execution status of this line is deduced): QByteArray qop = options.value("qop"); | - |
679 | | - |
680 | // qDebug() << "calculating digest: method=" << method << "path=" << path; | - |
681 | QByteArray response = digestMd5ResponseHelper(options.value("algorithm"), user.toLatin1(), executed (the execution status of this line is deduced): QByteArray response = digestMd5ResponseHelper(options.value("algorithm"), user.toLatin1(), | - |
682 | realm.toLatin1(), password.toLatin1(), executed (the execution status of this line is deduced): realm.toLatin1(), password.toLatin1(), | - |
683 | nonce, nonceCountString, executed (the execution status of this line is deduced): nonce, nonceCountString, | - |
684 | cnonce, qop, method, executed (the execution status of this line is deduced): cnonce, qop, method, | - |
685 | path, QByteArray()); executed (the execution status of this line is deduced): path, QByteArray()); | - |
686 | | - |
687 | | - |
688 | QByteArray credentials; executed (the execution status of this line is deduced): QByteArray credentials; | - |
689 | credentials += "username=\"" + user.toLatin1() + "\", "; executed (the execution status of this line is deduced): credentials += "username=\"" + user.toLatin1() + "\", "; | - |
690 | credentials += "realm=\"" + realm.toLatin1() + "\", "; executed (the execution status of this line is deduced): credentials += "realm=\"" + realm.toLatin1() + "\", "; | - |
691 | credentials += "nonce=\"" + nonce + "\", "; executed (the execution status of this line is deduced): credentials += "nonce=\"" + nonce + "\", "; | - |
692 | credentials += "uri=\"" + path + "\", "; executed (the execution status of this line is deduced): credentials += "uri=\"" + path + "\", "; | - |
693 | if (!opaque.isEmpty()) partially evaluated: !opaque.isEmpty() no Evaluation Count:0 | yes Evaluation Count:33 |
| 0-33 |
694 | credentials += "opaque=\"" + opaque + "\", "; never executed: credentials += "opaque=\"" + opaque + "\", "; | 0 |
695 | credentials += "response=\"" + response + '\"'; executed (the execution status of this line is deduced): credentials += "response=\"" + response + '\"'; | - |
696 | if (!options.value("algorithm").isEmpty()) partially evaluated: !options.value("algorithm").isEmpty() yes Evaluation Count:33 | no Evaluation Count:0 |
| 0-33 |
697 | credentials += ", algorithm=" + options.value("algorithm"); executed: credentials += ", algorithm=" + options.value("algorithm"); Execution Count:33 | 33 |
698 | if (!options.value("qop").isEmpty()) { partially evaluated: !options.value("qop").isEmpty() yes Evaluation Count:33 | no Evaluation Count:0 |
| 0-33 |
699 | credentials += ", qop=" + qop + ", "; executed (the execution status of this line is deduced): credentials += ", qop=" + qop + ", "; | - |
700 | credentials += "nc=" + nonceCountString + ", "; executed (the execution status of this line is deduced): credentials += "nc=" + nonceCountString + ", "; | - |
701 | credentials += "cnonce=\"" + cnonce + '\"'; executed (the execution status of this line is deduced): credentials += "cnonce=\"" + cnonce + '\"'; | - |
702 | } executed: } Execution Count:33 | 33 |
703 | | - |
704 | return credentials; executed: return credentials; Execution Count:33 | 33 |
705 | } | - |
706 | | - |
707 | // ---------------------------- Digest Md5 code ---------------------------------------- | - |
708 | | - |
709 | | - |
710 | | - |
711 | /* | - |
712 | * NTLM message flags. | - |
713 | * | - |
714 | * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru> | - |
715 | * | - |
716 | * This software is released under the MIT license. | - |
717 | */ | - |
718 | | - |
719 | /* | - |
720 | * Indicates that Unicode strings are supported for use in security | - |
721 | * buffer data. | - |
722 | */ | - |
723 | #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 | - |
724 | | - |
725 | /* | - |
726 | * Indicates that OEM strings are supported for use in security buffer data. | - |
727 | */ | - |
728 | #define NTLMSSP_NEGOTIATE_OEM 0x00000002 | - |
729 | | - |
730 | /* | - |
731 | * Requests that the server's authentication realm be included in the | - |
732 | * Type 2 message. | - |
733 | */ | - |
734 | #define NTLMSSP_REQUEST_TARGET 0x00000004 | - |
735 | | - |
736 | /* | - |
737 | * Specifies that authenticated communication between the client and server | - |
738 | * should carry a digital signature (message integrity). | - |
739 | */ | - |
740 | #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 | - |
741 | | - |
742 | /* | - |
743 | * Specifies that authenticated communication between the client and server | - |
744 | * should be encrypted (message confidentiality). | - |
745 | */ | - |
746 | #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 | - |
747 | | - |
748 | /* | - |
749 | * Indicates that datagram authentication is being used. | - |
750 | */ | - |
751 | #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 | - |
752 | | - |
753 | /* | - |
754 | * Indicates that the LAN Manager session key should be | - |
755 | * used for signing and sealing authenticated communications. | - |
756 | */ | - |
757 | #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 | - |
758 | | - |
759 | /* | - |
760 | * Indicates that NTLM authentication is being used. | - |
761 | */ | - |
762 | #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 | - |
763 | | - |
764 | /* | - |
765 | * Sent by the client in the Type 1 message to indicate that the name of the | - |
766 | * domain in which the client workstation has membership is included in the | - |
767 | * message. This is used by the server to determine whether the client is | - |
768 | * eligible for local authentication. | - |
769 | */ | - |
770 | #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 | - |
771 | | - |
772 | /* | - |
773 | * Sent by the client in the Type 1 message to indicate that the client | - |
774 | * workstation's name is included in the message. This is used by the server | - |
775 | * to determine whether the client is eligible for local authentication. | - |
776 | */ | - |
777 | #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 | - |
778 | | - |
779 | /* | - |
780 | * Sent by the server to indicate that the server and client are on the same | - |
781 | * machine. Implies that the client may use the established local credentials | - |
782 | * for authentication instead of calculating a response to the challenge. | - |
783 | */ | - |
784 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000 | - |
785 | | - |
786 | /* | - |
787 | * Indicates that authenticated communication between the client and server | - |
788 | * should be signed with a "dummy" signature. | - |
789 | */ | - |
790 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 | - |
791 | | - |
792 | /* | - |
793 | * Sent by the server in the Type 2 message to indicate that the target | - |
794 | * authentication realm is a domain. | - |
795 | */ | - |
796 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 | - |
797 | | - |
798 | /* | - |
799 | * Sent by the server in the Type 2 message to indicate that the target | - |
800 | * authentication realm is a server. | - |
801 | */ | - |
802 | #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 | - |
803 | | - |
804 | /* | - |
805 | * Sent by the server in the Type 2 message to indicate that the target | - |
806 | * authentication realm is a share. Presumably, this is for share-level | - |
807 | * authentication. Usage is unclear. | - |
808 | */ | - |
809 | #define NTLMSSP_TARGET_TYPE_SHARE 0x00040000 | - |
810 | | - |
811 | /* | - |
812 | * Indicates that the NTLM2 signing and sealing scheme should be used for | - |
813 | * protecting authenticated communications. Note that this refers to a | - |
814 | * particular session security scheme, and is not related to the use of | - |
815 | * NTLMv2 authentication. | - |
816 | */ | - |
817 | #define NTLMSSP_NEGOTIATE_NTLM2 0x00080000 | - |
818 | | - |
819 | /* | - |
820 | * Sent by the server in the Type 2 message to indicate that it is including | - |
821 | * a Target Information block in the message. The Target Information block | - |
822 | * is used in the calculation of the NTLMv2 response. | - |
823 | */ | - |
824 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 | - |
825 | | - |
826 | /* | - |
827 | * Indicates that 128-bit encryption is supported. | - |
828 | */ | - |
829 | #define NTLMSSP_NEGOTIATE_128 0x20000000 | - |
830 | | - |
831 | /* | - |
832 | * Indicates that the client will provide an encrypted master session key in | - |
833 | * the "Session Key" field of the Type 3 message. This is used in signing and | - |
834 | * sealing, and is RC4-encrypted using the previous session key as the | - |
835 | * encryption key. | - |
836 | */ | - |
837 | #define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000 | - |
838 | | - |
839 | /* | - |
840 | * Indicates that 56-bit encryption is supported. | - |
841 | */ | - |
842 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | - |
843 | | - |
844 | /* | - |
845 | * AvId values | - |
846 | */ | - |
847 | #define AVTIMESTAMP 7 | - |
848 | | - |
849 | //#define NTLMV1_CLIENT | - |
850 | | - |
851 | | - |
852 | //************************Global variables*************************** | - |
853 | | - |
854 | const int blockSize = 64; //As per RFC2104 Block-size is 512 bits | - |
855 | const int nDigestLen = 16; //Trunctaion Length of the Hmac-Md5 digest | - |
856 | const quint8 respversion = 1; | - |
857 | const quint8 hirespversion = 1; | - |
858 | | - |
859 | /* usage: | - |
860 | // fill up ctx with what we know. | - |
861 | QByteArray response = qNtlmPhase1(ctx); | - |
862 | // send response (b64 encoded??) | - |
863 | // get response from server (b64 decode?) | - |
864 | Phase2Block pb; | - |
865 | qNtlmDecodePhase2(response, pb); | - |
866 | response = qNtlmPhase3(ctx, pb); | - |
867 | // send response (b64 encoded??) | - |
868 | */ | - |
869 | | - |
870 | /* | - |
871 | TODO: | - |
872 | - Fix unicode handling | - |
873 | - add v2 handling | - |
874 | */ | - |
875 | | - |
876 | class QNtlmBuffer { | - |
877 | public: | - |
878 | QNtlmBuffer() : len(0), maxLen(0), offset(0) {} | 0 |
879 | quint16 len; | - |
880 | quint16 maxLen; | - |
881 | quint32 offset; | - |
882 | enum { Size = 8 }; | - |
883 | }; | - |
884 | | - |
885 | class QNtlmPhase1BlockBase | - |
886 | { | - |
887 | public: | - |
888 | char magic[8]; | - |
889 | quint32 type; | - |
890 | quint32 flags; | - |
891 | QNtlmBuffer domain; | - |
892 | QNtlmBuffer workstation; | - |
893 | enum { Size = 32 }; | - |
894 | }; | - |
895 | | - |
896 | // ################# check paddings | - |
897 | class QNtlmPhase2BlockBase | - |
898 | { | - |
899 | public: | - |
900 | char magic[8]; | - |
901 | quint32 type; | - |
902 | QNtlmBuffer targetName; | - |
903 | quint32 flags; | - |
904 | unsigned char challenge[8]; | - |
905 | quint32 context[2]; | - |
906 | QNtlmBuffer targetInfo; | - |
907 | enum { Size = 48 }; | - |
908 | }; | - |
909 | | - |
910 | class QNtlmPhase3BlockBase { | - |
911 | public: | - |
912 | char magic[8]; | - |
913 | quint32 type; | - |
914 | QNtlmBuffer lmResponse; | - |
915 | QNtlmBuffer ntlmResponse; | - |
916 | QNtlmBuffer domain; | - |
917 | QNtlmBuffer user; | - |
918 | QNtlmBuffer workstation; | - |
919 | QNtlmBuffer sessionKey; | - |
920 | quint32 flags; | - |
921 | enum { Size = 64 }; | - |
922 | }; | - |
923 | | - |
924 | static void qStreamNtlmBuffer(QDataStream& ds, const QByteArray& s) | - |
925 | { | - |
926 | ds.writeRawData(s.constData(), s.size()); never executed (the execution status of this line is deduced): ds.writeRawData(s.constData(), s.size()); | - |
927 | } | 0 |
928 | | - |
929 | | - |
930 | static void qStreamNtlmString(QDataStream& ds, const QString& s, bool unicode) | - |
931 | { | - |
932 | if (!unicode) { never evaluated: !unicode | 0 |
933 | qStreamNtlmBuffer(ds, s.toLatin1()); never executed (the execution status of this line is deduced): qStreamNtlmBuffer(ds, s.toLatin1()); | - |
934 | return; | 0 |
935 | } | - |
936 | const ushort *d = s.utf16(); never executed (the execution status of this line is deduced): const ushort *d = s.utf16(); | - |
937 | for (int i = 0; i < s.length(); ++i) never evaluated: i < s.length() | 0 |
938 | ds << d[i]; never executed: ds << d[i]; | 0 |
939 | } | 0 |
940 | | - |
941 | | - |
942 | | - |
943 | static int qEncodeNtlmBuffer(QNtlmBuffer& buf, int offset, const QByteArray& s) | - |
944 | { | - |
945 | buf.len = s.size(); never executed (the execution status of this line is deduced): buf.len = s.size(); | - |
946 | buf.maxLen = buf.len; never executed (the execution status of this line is deduced): buf.maxLen = buf.len; | - |
947 | buf.offset = (offset + 1) & ~1; never executed (the execution status of this line is deduced): buf.offset = (offset + 1) & ~1; | - |
948 | return buf.offset + buf.len; never executed: return buf.offset + buf.len; | 0 |
949 | } | - |
950 | | - |
951 | | - |
952 | static int qEncodeNtlmString(QNtlmBuffer& buf, int offset, const QString& s, bool unicode) | - |
953 | { | - |
954 | if (!unicode) never evaluated: !unicode | 0 |
955 | return qEncodeNtlmBuffer(buf, offset, s.toLatin1()); never executed: return qEncodeNtlmBuffer(buf, offset, s.toLatin1()); | 0 |
956 | buf.len = 2 * s.length(); never executed (the execution status of this line is deduced): buf.len = 2 * s.length(); | - |
957 | buf.maxLen = buf.len; never executed (the execution status of this line is deduced): buf.maxLen = buf.len; | - |
958 | buf.offset = (offset + 1) & ~1; never executed (the execution status of this line is deduced): buf.offset = (offset + 1) & ~1; | - |
959 | return buf.offset + buf.len; never executed: return buf.offset + buf.len; | 0 |
960 | } | - |
961 | | - |
962 | | - |
963 | static QDataStream& operator<<(QDataStream& s, const QNtlmBuffer& b) | - |
964 | { | - |
965 | s << b.len << b.maxLen << b.offset; never executed (the execution status of this line is deduced): s << b.len << b.maxLen << b.offset; | - |
966 | return s; never executed: return s; | 0 |
967 | } | - |
968 | | - |
969 | static QDataStream& operator>>(QDataStream& s, QNtlmBuffer& b) | - |
970 | { | - |
971 | s >> b.len >> b.maxLen >> b.offset; never executed (the execution status of this line is deduced): s >> b.len >> b.maxLen >> b.offset; | - |
972 | return s; never executed: return s; | 0 |
973 | } | - |
974 | | - |
975 | | - |
976 | class QNtlmPhase1Block : public QNtlmPhase1BlockBase | - |
977 | { // request | - |
978 | public: | - |
979 | QNtlmPhase1Block() { | - |
980 | qstrncpy(magic, "NTLMSSP", 8); never executed (the execution status of this line is deduced): qstrncpy(magic, "NTLMSSP", 8); | - |
981 | type = 1; never executed (the execution status of this line is deduced): type = 1; | - |
982 | flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET; never executed (the execution status of this line is deduced): flags = 0x00000001 | 0x00000200 | 0x00000004; | - |
983 | } | 0 |
984 | | - |
985 | // extracted | - |
986 | QString domainStr, workstationStr; | - |
987 | }; | - |
988 | | - |
989 | | - |
990 | class QNtlmPhase2Block : public QNtlmPhase2BlockBase | - |
991 | { // challenge | - |
992 | public: | - |
993 | QNtlmPhase2Block() { | - |
994 | magic[0] = 0; never executed (the execution status of this line is deduced): magic[0] = 0; | - |
995 | type = 0xffffffff; never executed (the execution status of this line is deduced): type = 0xffffffff; | - |
996 | } | 0 |
997 | | - |
998 | // extracted | - |
999 | QString targetNameStr, targetInfoStr; | - |
1000 | QByteArray targetInfoBuff; | - |
1001 | }; | - |
1002 | | - |
1003 | | - |
1004 | | - |
1005 | class QNtlmPhase3Block : public QNtlmPhase3BlockBase { // response | - |
1006 | public: | - |
1007 | QNtlmPhase3Block() { | - |
1008 | qstrncpy(magic, "NTLMSSP", 8); never executed (the execution status of this line is deduced): qstrncpy(magic, "NTLMSSP", 8); | - |
1009 | type = 3; never executed (the execution status of this line is deduced): type = 3; | - |
1010 | flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO; never executed (the execution status of this line is deduced): flags = 0x00000001 | 0x00000200 | 0x00800000; | - |
1011 | } | 0 |
1012 | | - |
1013 | // extracted | - |
1014 | QByteArray lmResponseBuf, ntlmResponseBuf; | - |
1015 | QString domainStr, userStr, workstationStr, sessionKeyStr; | - |
1016 | QByteArray v2Hash; | - |
1017 | }; | - |
1018 | | - |
1019 | | - |
1020 | static QDataStream& operator<<(QDataStream& s, const QNtlmPhase1Block& b) { | - |
1021 | bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE); never executed (the execution status of this line is deduced): bool unicode = (b.flags & 0x00000001); | - |
1022 | | - |
1023 | s.writeRawData(b.magic, sizeof(b.magic)); never executed (the execution status of this line is deduced): s.writeRawData(b.magic, sizeof(b.magic)); | - |
1024 | s << b.type; never executed (the execution status of this line is deduced): s << b.type; | - |
1025 | s << b.flags; never executed (the execution status of this line is deduced): s << b.flags; | - |
1026 | s << b.domain; never executed (the execution status of this line is deduced): s << b.domain; | - |
1027 | s << b.workstation; never executed (the execution status of this line is deduced): s << b.workstation; | - |
1028 | if (!b.domainStr.isEmpty()) never evaluated: !b.domainStr.isEmpty() | 0 |
1029 | qStreamNtlmString(s, b.domainStr, unicode); never executed: qStreamNtlmString(s, b.domainStr, unicode); | 0 |
1030 | if (!b.workstationStr.isEmpty()) never evaluated: !b.workstationStr.isEmpty() | 0 |
1031 | qStreamNtlmString(s, b.workstationStr, unicode); never executed: qStreamNtlmString(s, b.workstationStr, unicode); | 0 |
1032 | return s; never executed: return s; | 0 |
1033 | } | - |
1034 | | - |
1035 | | - |
1036 | static QDataStream& operator<<(QDataStream& s, const QNtlmPhase3Block& b) { | - |
1037 | bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE); never executed (the execution status of this line is deduced): bool unicode = (b.flags & 0x00000001); | - |
1038 | s.writeRawData(b.magic, sizeof(b.magic)); never executed (the execution status of this line is deduced): s.writeRawData(b.magic, sizeof(b.magic)); | - |
1039 | s << b.type; never executed (the execution status of this line is deduced): s << b.type; | - |
1040 | s << b.lmResponse; never executed (the execution status of this line is deduced): s << b.lmResponse; | - |
1041 | s << b.ntlmResponse; never executed (the execution status of this line is deduced): s << b.ntlmResponse; | - |
1042 | s << b.domain; never executed (the execution status of this line is deduced): s << b.domain; | - |
1043 | s << b.user; never executed (the execution status of this line is deduced): s << b.user; | - |
1044 | s << b.workstation; never executed (the execution status of this line is deduced): s << b.workstation; | - |
1045 | s << b.sessionKey; never executed (the execution status of this line is deduced): s << b.sessionKey; | - |
1046 | s << b.flags; never executed (the execution status of this line is deduced): s << b.flags; | - |
1047 | | - |
1048 | if (!b.domainStr.isEmpty()) never evaluated: !b.domainStr.isEmpty() | 0 |
1049 | qStreamNtlmString(s, b.domainStr, unicode); never executed: qStreamNtlmString(s, b.domainStr, unicode); | 0 |
1050 | | - |
1051 | qStreamNtlmString(s, b.userStr, unicode); never executed (the execution status of this line is deduced): qStreamNtlmString(s, b.userStr, unicode); | - |
1052 | | - |
1053 | if (!b.workstationStr.isEmpty()) never evaluated: !b.workstationStr.isEmpty() | 0 |
1054 | qStreamNtlmString(s, b.workstationStr, unicode); never executed: qStreamNtlmString(s, b.workstationStr, unicode); | 0 |
1055 | | - |
1056 | // Send auth info | - |
1057 | qStreamNtlmBuffer(s, b.lmResponseBuf); never executed (the execution status of this line is deduced): qStreamNtlmBuffer(s, b.lmResponseBuf); | - |
1058 | qStreamNtlmBuffer(s, b.ntlmResponseBuf); never executed (the execution status of this line is deduced): qStreamNtlmBuffer(s, b.ntlmResponseBuf); | - |
1059 | | - |
1060 | | - |
1061 | return s; never executed: return s; | 0 |
1062 | } | - |
1063 | | - |
1064 | | - |
1065 | static QByteArray qNtlmPhase1() | - |
1066 | { | - |
1067 | QByteArray rc; never executed (the execution status of this line is deduced): QByteArray rc; | - |
1068 | QDataStream ds(&rc, QIODevice::WriteOnly); never executed (the execution status of this line is deduced): QDataStream ds(&rc, QIODevice::WriteOnly); | - |
1069 | ds.setByteOrder(QDataStream::LittleEndian); never executed (the execution status of this line is deduced): ds.setByteOrder(QDataStream::LittleEndian); | - |
1070 | QNtlmPhase1Block pb; never executed (the execution status of this line is deduced): QNtlmPhase1Block pb; | - |
1071 | ds << pb; never executed (the execution status of this line is deduced): ds << pb; | - |
1072 | return rc; never executed: return rc; | 0 |
1073 | } | - |
1074 | | - |
1075 | | - |
1076 | static QByteArray qStringAsUcs2Le(const QString& src) | - |
1077 | { | - |
1078 | QByteArray rc(2*src.length(), 0); never executed (the execution status of this line is deduced): QByteArray rc(2*src.length(), 0); | - |
1079 | const unsigned short *s = src.utf16(); never executed (the execution status of this line is deduced): const unsigned short *s = src.utf16(); | - |
1080 | unsigned short *d = (unsigned short*)rc.data(); never executed (the execution status of this line is deduced): unsigned short *d = (unsigned short*)rc.data(); | - |
1081 | for (int i = 0; i < src.length(); ++i) { never evaluated: i < src.length() | 0 |
1082 | d[i] = qToLittleEndian(s[i]); never executed (the execution status of this line is deduced): d[i] = qToLittleEndian(s[i]); | - |
1083 | } | 0 |
1084 | return rc; never executed: return rc; | 0 |
1085 | } | - |
1086 | | - |
1087 | | - |
1088 | static QString qStringFromUcs2Le(const QByteArray& src) | - |
1089 | { | - |
1090 | Q_ASSERT(src.size() % 2 == 0); never executed (the execution status of this line is deduced): qt_noop(); | - |
1091 | unsigned short *d = (unsigned short*)src.data(); never executed (the execution status of this line is deduced): unsigned short *d = (unsigned short*)src.data(); | - |
1092 | for (int i = 0; i < src.length() / 2; ++i) { never evaluated: i < src.length() / 2 | 0 |
1093 | d[i] = qFromLittleEndian(d[i]); never executed (the execution status of this line is deduced): d[i] = qFromLittleEndian(d[i]); | - |
1094 | } | 0 |
1095 | return QString((const QChar *)src.data(), src.size()/2); never executed: return QString((const QChar *)src.data(), src.size()/2); | 0 |
1096 | } | - |
1097 | | - |
1098 | #ifdef NTLMV1_CLIENT | - |
1099 | static QByteArray qEncodeNtlmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch) | - |
1100 | { | - |
1101 | QCryptographicHash md4(QCryptographicHash::Md4); | - |
1102 | QByteArray asUcs2Le = qStringAsUcs2Le(ctx->password); | - |
1103 | md4.addData(asUcs2Le.data(), asUcs2Le.size()); | - |
1104 | | - |
1105 | unsigned char md4hash[22]; | - |
1106 | memset(md4hash, 0, sizeof(md4hash)); | - |
1107 | QByteArray hash = md4.result(); | - |
1108 | Q_ASSERT(hash.size() == 16); | - |
1109 | memcpy(md4hash, hash.constData(), 16); | - |
1110 | | - |
1111 | QByteArray rc(24, 0); | - |
1112 | deshash((unsigned char *)rc.data(), md4hash, (unsigned char *)ch.challenge); | - |
1113 | deshash((unsigned char *)rc.data() + 8, md4hash + 7, (unsigned char *)ch.challenge); | - |
1114 | deshash((unsigned char *)rc.data() + 16, md4hash + 14, (unsigned char *)ch.challenge); | - |
1115 | | - |
1116 | hash.fill(0); | - |
1117 | return rc; | - |
1118 | } | - |
1119 | | - |
1120 | | - |
1121 | static QByteArray qEncodeLmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch) | - |
1122 | { | - |
1123 | QByteArray hash(21, 0); | - |
1124 | QByteArray key(14, 0); | - |
1125 | qstrncpy(key.data(), ctx->password.toUpper().toLatin1(), 14); | - |
1126 | const char *block = "KGS!@#$%"; | - |
1127 | | - |
1128 | deshash((unsigned char *)hash.data(), (unsigned char *)key.data(), (unsigned char *)block); | - |
1129 | deshash((unsigned char *)hash.data() + 8, (unsigned char *)key.data() + 7, (unsigned char *)block); | - |
1130 | key.fill(0); | - |
1131 | | - |
1132 | QByteArray rc(24, 0); | - |
1133 | deshash((unsigned char *)rc.data(), (unsigned char *)hash.data(), ch.challenge); | - |
1134 | deshash((unsigned char *)rc.data() + 8, (unsigned char *)hash.data() + 7, ch.challenge); | - |
1135 | deshash((unsigned char *)rc.data() + 16, (unsigned char *)hash.data() + 14, ch.challenge); | - |
1136 | | - |
1137 | hash.fill(0); | - |
1138 | return rc; | - |
1139 | } | - |
1140 | #endif | - |
1141 | | - |
1142 | /********************************************************************* | - |
1143 | * Function Name: qEncodeHmacMd5 | - |
1144 | * Params: | - |
1145 | * key: Type - QByteArray | - |
1146 | * - It is the Authentication key | - |
1147 | * message: Type - QByteArray | - |
1148 | * - This is the actual message which will be encoded | - |
1149 | * using HMacMd5 hash algorithm | - |
1150 | * | - |
1151 | * Return Value: | - |
1152 | * hmacDigest: Type - QByteArray | - |
1153 | * | - |
1154 | * Description: | - |
1155 | * This function will be used to encode the input message using | - |
1156 | * HMacMd5 hash algorithm. | - |
1157 | * | - |
1158 | * As per the RFC2104 the HMacMd5 algorithm can be specified | - |
1159 | * --------------------------------------- | - |
1160 | * MD5(K XOR opad, MD5(K XOR ipad, text)) | - |
1161 | * --------------------------------------- | - |
1162 | * | - |
1163 | *********************************************************************/ | - |
1164 | QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message) | - |
1165 | { | - |
1166 | Q_ASSERT_X(!(message.isEmpty()),"qEncodeHmacMd5", "Empty message check"); never executed (the execution status of this line is deduced): qt_noop(); | - |
1167 | Q_ASSERT_X(!(key.isEmpty()),"qEncodeHmacMd5", "Empty key check"); never executed (the execution status of this line is deduced): qt_noop(); | - |
1168 | | - |
1169 | QCryptographicHash hash(QCryptographicHash::Md5); never executed (the execution status of this line is deduced): QCryptographicHash hash(QCryptographicHash::Md5); | - |
1170 | QByteArray hMsg; never executed (the execution status of this line is deduced): QByteArray hMsg; | - |
1171 | | - |
1172 | QByteArray iKeyPad(blockSize, 0x36); never executed (the execution status of this line is deduced): QByteArray iKeyPad(blockSize, 0x36); | - |
1173 | QByteArray oKeyPad(blockSize, 0x5c); never executed (the execution status of this line is deduced): QByteArray oKeyPad(blockSize, 0x5c); | - |
1174 | | - |
1175 | hash.reset(); never executed (the execution status of this line is deduced): hash.reset(); | - |
1176 | // Adjust the key length to blockSize | - |
1177 | | - |
1178 | if(blockSize < key.length()) { never evaluated: blockSize < key.length() | 0 |
1179 | hash.addData(key); never executed (the execution status of this line is deduced): hash.addData(key); | - |
1180 | key = hash.result(); //MD5 will always return 16 bytes length output never executed (the execution status of this line is deduced): key = hash.result(); | - |
1181 | } | 0 |
1182 | | - |
1183 | //Key will be <= 16 or 20 bytes as hash function (MD5 or SHA hash algorithms) | - |
1184 | //key size can be max of Block size only | - |
1185 | key = key.leftJustified(blockSize,0,true); never executed (the execution status of this line is deduced): key = key.leftJustified(blockSize,0,true); | - |
1186 | | - |
1187 | //iKeyPad, oKeyPad and key are all of same size "blockSize" | - |
1188 | | - |
1189 | //xor of iKeyPad with Key and store the result into iKeyPad | - |
1190 | for(int i = 0; i<key.size();i++) { never evaluated: i<key.size() | 0 |
1191 | iKeyPad[i] = key[i]^iKeyPad[i]; never executed (the execution status of this line is deduced): iKeyPad[i] = key[i]^iKeyPad[i]; | - |
1192 | } | 0 |
1193 | | - |
1194 | //xor of oKeyPad with Key and store the result into oKeyPad | - |
1195 | for(int i = 0; i<key.size();i++) { never evaluated: i<key.size() | 0 |
1196 | oKeyPad[i] = key[i]^oKeyPad[i]; never executed (the execution status of this line is deduced): oKeyPad[i] = key[i]^oKeyPad[i]; | - |
1197 | } | 0 |
1198 | | - |
1199 | iKeyPad.append(message); // (K0 xor ipad) || text never executed (the execution status of this line is deduced): iKeyPad.append(message); | - |
1200 | | - |
1201 | hash.reset(); never executed (the execution status of this line is deduced): hash.reset(); | - |
1202 | hash.addData(iKeyPad); never executed (the execution status of this line is deduced): hash.addData(iKeyPad); | - |
1203 | hMsg = hash.result(); never executed (the execution status of this line is deduced): hMsg = hash.result(); | - |
1204 | //Digest gen after pass-1: H((K0 xor ipad)||text) | - |
1205 | | - |
1206 | QByteArray hmacDigest; never executed (the execution status of this line is deduced): QByteArray hmacDigest; | - |
1207 | oKeyPad.append(hMsg); never executed (the execution status of this line is deduced): oKeyPad.append(hMsg); | - |
1208 | hash.reset(); never executed (the execution status of this line is deduced): hash.reset(); | - |
1209 | hash.addData(oKeyPad); never executed (the execution status of this line is deduced): hash.addData(oKeyPad); | - |
1210 | hmacDigest = hash.result(); never executed (the execution status of this line is deduced): hmacDigest = hash.result(); | - |
1211 | // H((K0 xor opad )|| H((K0 xor ipad) || text)) | - |
1212 | | - |
1213 | /*hmacDigest should not be less than half the length of the HMAC output | - |
1214 | (to match the birthday attack bound) and not less than 80 bits | - |
1215 | (a suitable lower bound on the number of bits that need to be | - |
1216 | predicted by an attacker). | - |
1217 | Refer RFC 2104 for more details on truncation part */ | - |
1218 | | - |
1219 | /*MD5 hash always returns 16 byte digest only and HMAC-MD5 spec | - |
1220 | (RFC 2104) also says digest length should be 16 bytes*/ | - |
1221 | return hmacDigest; never executed: return hmacDigest; | 0 |
1222 | } | - |
1223 | | - |
1224 | static QByteArray qCreatev2Hash(const QAuthenticatorPrivate *ctx, | - |
1225 | QNtlmPhase3Block *phase3) | - |
1226 | { | - |
1227 | Q_ASSERT(phase3 != 0); never executed (the execution status of this line is deduced): qt_noop(); | - |
1228 | // since v2 Hash is need for both NTLMv2 and LMv2 it is calculated | - |
1229 | // only once and stored and reused | - |
1230 | if(phase3->v2Hash.size() == 0) { never evaluated: phase3->v2Hash.size() == 0 | 0 |
1231 | QCryptographicHash md4(QCryptographicHash::Md4); never executed (the execution status of this line is deduced): QCryptographicHash md4(QCryptographicHash::Md4); | - |
1232 | QByteArray passUnicode = qStringAsUcs2Le(ctx->password); never executed (the execution status of this line is deduced): QByteArray passUnicode = qStringAsUcs2Le(ctx->password); | - |
1233 | md4.addData(passUnicode.data(), passUnicode.size()); never executed (the execution status of this line is deduced): md4.addData(passUnicode.data(), passUnicode.size()); | - |
1234 | | - |
1235 | QByteArray hashKey = md4.result(); never executed (the execution status of this line is deduced): QByteArray hashKey = md4.result(); | - |
1236 | Q_ASSERT(hashKey.size() == 16); never executed (the execution status of this line is deduced): qt_noop(); | - |
1237 | // Assuming the user and domain is always unicode in challenge | - |
1238 | QByteArray message = never executed (the execution status of this line is deduced): QByteArray message = | - |
1239 | qStringAsUcs2Le(ctx->extractedUser.toUpper()) + never executed (the execution status of this line is deduced): qStringAsUcs2Le(ctx->extractedUser.toUpper()) + | - |
1240 | qStringAsUcs2Le(phase3->domainStr); never executed (the execution status of this line is deduced): qStringAsUcs2Le(phase3->domainStr); | - |
1241 | | - |
1242 | phase3->v2Hash = qEncodeHmacMd5(hashKey, message); never executed (the execution status of this line is deduced): phase3->v2Hash = qEncodeHmacMd5(hashKey, message); | - |
1243 | } | 0 |
1244 | return phase3->v2Hash; never executed: return phase3->v2Hash; | 0 |
1245 | } | - |
1246 | | - |
1247 | static QByteArray clientChallenge(const QAuthenticatorPrivate *ctx) | - |
1248 | { | - |
1249 | Q_ASSERT(ctx->cnonce.size() >= 8); never executed (the execution status of this line is deduced): qt_noop(); | - |
1250 | QByteArray clientCh = ctx->cnonce.right(8); never executed (the execution status of this line is deduced): QByteArray clientCh = ctx->cnonce.right(8); | - |
1251 | return clientCh; never executed: return clientCh; | 0 |
1252 | } | - |
1253 | | - |
1254 | // caller has to ensure a valid targetInfoBuff | - |
1255 | static QByteArray qExtractServerTime(const QByteArray& targetInfoBuff) | - |
1256 | { | - |
1257 | QByteArray timeArray; never executed (the execution status of this line is deduced): QByteArray timeArray; | - |
1258 | QDataStream ds(targetInfoBuff); never executed (the execution status of this line is deduced): QDataStream ds(targetInfoBuff); | - |
1259 | ds.setByteOrder(QDataStream::LittleEndian); never executed (the execution status of this line is deduced): ds.setByteOrder(QDataStream::LittleEndian); | - |
1260 | | - |
1261 | quint16 avId; never executed (the execution status of this line is deduced): quint16 avId; | - |
1262 | quint16 avLen; never executed (the execution status of this line is deduced): quint16 avLen; | - |
1263 | | - |
1264 | ds >> avId; never executed (the execution status of this line is deduced): ds >> avId; | - |
1265 | ds >> avLen; never executed (the execution status of this line is deduced): ds >> avLen; | - |
1266 | while(avId != 0) { never evaluated: avId != 0 | 0 |
1267 | if(avId == AVTIMESTAMP) { never evaluated: avId == 7 | 0 |
1268 | timeArray.resize(avLen); never executed (the execution status of this line is deduced): timeArray.resize(avLen); | - |
1269 | //avLen size of QByteArray is allocated | - |
1270 | ds.readRawData(timeArray.data(), avLen); never executed (the execution status of this line is deduced): ds.readRawData(timeArray.data(), avLen); | - |
1271 | break; | 0 |
1272 | } | - |
1273 | ds.skipRawData(avLen); never executed (the execution status of this line is deduced): ds.skipRawData(avLen); | - |
1274 | ds >> avId; never executed (the execution status of this line is deduced): ds >> avId; | - |
1275 | ds >> avLen; never executed (the execution status of this line is deduced): ds >> avLen; | - |
1276 | } | 0 |
1277 | return timeArray; never executed: return timeArray; | 0 |
1278 | } | - |
1279 | | - |
1280 | static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx, | - |
1281 | const QNtlmPhase2Block& ch, | - |
1282 | QNtlmPhase3Block *phase3) | - |
1283 | { | - |
1284 | Q_ASSERT(phase3 != 0); never executed (the execution status of this line is deduced): qt_noop(); | - |
1285 | // return value stored in phase3 | - |
1286 | qCreatev2Hash(ctx, phase3); never executed (the execution status of this line is deduced): qCreatev2Hash(ctx, phase3); | - |
1287 | | - |
1288 | QByteArray temp; never executed (the execution status of this line is deduced): QByteArray temp; | - |
1289 | QDataStream ds(&temp, QIODevice::WriteOnly); never executed (the execution status of this line is deduced): QDataStream ds(&temp, QIODevice::WriteOnly); | - |
1290 | ds.setByteOrder(QDataStream::LittleEndian); never executed (the execution status of this line is deduced): ds.setByteOrder(QDataStream::LittleEndian); | - |
1291 | | - |
1292 | ds << respversion; never executed (the execution status of this line is deduced): ds << respversion; | - |
1293 | ds << hirespversion; never executed (the execution status of this line is deduced): ds << hirespversion; | - |
1294 | | - |
1295 | //Reserved | - |
1296 | QByteArray reserved1(6, 0); never executed (the execution status of this line is deduced): QByteArray reserved1(6, 0); | - |
1297 | ds.writeRawData(reserved1.constData(), reserved1.size()); never executed (the execution status of this line is deduced): ds.writeRawData(reserved1.constData(), reserved1.size()); | - |
1298 | | - |
1299 | quint64 time = 0; never executed (the execution status of this line is deduced): quint64 time = 0; | - |
1300 | QByteArray timeArray; never executed (the execution status of this line is deduced): QByteArray timeArray; | - |
1301 | | - |
1302 | if(ch.targetInfo.len) never evaluated: ch.targetInfo.len | 0 |
1303 | { | - |
1304 | timeArray = qExtractServerTime(ch.targetInfoBuff); never executed (the execution status of this line is deduced): timeArray = qExtractServerTime(ch.targetInfoBuff); | - |
1305 | } | 0 |
1306 | | - |
1307 | //if server sends time, use it instead of current time | - |
1308 | if(timeArray.size()) { never evaluated: timeArray.size() | 0 |
1309 | ds.writeRawData(timeArray.constData(), timeArray.size()); never executed (the execution status of this line is deduced): ds.writeRawData(timeArray.constData(), timeArray.size()); | - |
1310 | } else { | 0 |
1311 | QDateTime currentTime(QDate::currentDate(), never executed (the execution status of this line is deduced): QDateTime currentTime(QDate::currentDate(), | - |
1312 | QTime::currentTime(), Qt::UTC); never executed (the execution status of this line is deduced): QTime::currentTime(), Qt::UTC); | - |
1313 | | - |
1314 | // number of seconds between 1601 and epoc(1970) | - |
1315 | // 369 years, 89 leap years | - |
1316 | // ((369 * 365) + 89) * 24 * 3600 = 11644473600 | - |
1317 | | - |
1318 | time = Q_UINT64_C(currentTime.toTime_t() + 11644473600); never executed (the execution status of this line is deduced): time = static_cast<unsigned long long>(currentTime.toTime_t() + 11644473600ULL); | - |
1319 | | - |
1320 | // represented as 100 nano seconds | - |
1321 | time = Q_UINT64_C(time * 10000000); never executed (the execution status of this line is deduced): time = static_cast<unsigned long long>(time * 10000000ULL); | - |
1322 | ds << time; never executed (the execution status of this line is deduced): ds << time; | - |
1323 | } | 0 |
1324 | | - |
1325 | //8 byte client challenge | - |
1326 | QByteArray clientCh = clientChallenge(ctx); never executed (the execution status of this line is deduced): QByteArray clientCh = clientChallenge(ctx); | - |
1327 | ds.writeRawData(clientCh.constData(), clientCh.size()); never executed (the execution status of this line is deduced): ds.writeRawData(clientCh.constData(), clientCh.size()); | - |
1328 | | - |
1329 | //Reserved | - |
1330 | QByteArray reserved2(4, 0); never executed (the execution status of this line is deduced): QByteArray reserved2(4, 0); | - |
1331 | ds.writeRawData(reserved2.constData(), reserved2.size()); never executed (the execution status of this line is deduced): ds.writeRawData(reserved2.constData(), reserved2.size()); | - |
1332 | | - |
1333 | if (ch.targetInfo.len > 0) { never evaluated: ch.targetInfo.len > 0 | 0 |
1334 | ds.writeRawData(ch.targetInfoBuff.constData(), never executed (the execution status of this line is deduced): ds.writeRawData(ch.targetInfoBuff.constData(), | - |
1335 | ch.targetInfoBuff.size()); never executed (the execution status of this line is deduced): ch.targetInfoBuff.size()); | - |
1336 | } | 0 |
1337 | | - |
1338 | //Reserved | - |
1339 | QByteArray reserved3(4, 0); never executed (the execution status of this line is deduced): QByteArray reserved3(4, 0); | - |
1340 | ds.writeRawData(reserved3.constData(), reserved3.size()); never executed (the execution status of this line is deduced): ds.writeRawData(reserved3.constData(), reserved3.size()); | - |
1341 | | - |
1342 | QByteArray message((const char*)ch.challenge, sizeof(ch.challenge)); never executed (the execution status of this line is deduced): QByteArray message((const char*)ch.challenge, sizeof(ch.challenge)); | - |
1343 | message.append(temp); never executed (the execution status of this line is deduced): message.append(temp); | - |
1344 | | - |
1345 | QByteArray ntChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message); never executed (the execution status of this line is deduced): QByteArray ntChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message); | - |
1346 | ntChallengeResp.append(temp); never executed (the execution status of this line is deduced): ntChallengeResp.append(temp); | - |
1347 | | - |
1348 | return ntChallengeResp; never executed: return ntChallengeResp; | 0 |
1349 | } | - |
1350 | | - |
1351 | static QByteArray qEncodeLmv2Response(const QAuthenticatorPrivate *ctx, | - |
1352 | const QNtlmPhase2Block& ch, | - |
1353 | QNtlmPhase3Block *phase3) | - |
1354 | { | - |
1355 | Q_ASSERT(phase3 != 0); never executed (the execution status of this line is deduced): qt_noop(); | - |
1356 | // return value stored in phase3 | - |
1357 | qCreatev2Hash(ctx, phase3); never executed (the execution status of this line is deduced): qCreatev2Hash(ctx, phase3); | - |
1358 | | - |
1359 | QByteArray message((const char*)ch.challenge, sizeof(ch.challenge)); never executed (the execution status of this line is deduced): QByteArray message((const char*)ch.challenge, sizeof(ch.challenge)); | - |
1360 | QByteArray clientCh = clientChallenge(ctx); never executed (the execution status of this line is deduced): QByteArray clientCh = clientChallenge(ctx); | - |
1361 | | - |
1362 | message.append(clientCh); never executed (the execution status of this line is deduced): message.append(clientCh); | - |
1363 | | - |
1364 | QByteArray lmChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message); never executed (the execution status of this line is deduced): QByteArray lmChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message); | - |
1365 | lmChallengeResp.append(clientCh); never executed (the execution status of this line is deduced): lmChallengeResp.append(clientCh); | - |
1366 | | - |
1367 | return lmChallengeResp; never executed: return lmChallengeResp; | 0 |
1368 | } | - |
1369 | | - |
1370 | static bool qNtlmDecodePhase2(const QByteArray& data, QNtlmPhase2Block& ch) | - |
1371 | { | - |
1372 | Q_ASSERT(QNtlmPhase2BlockBase::Size == sizeof(QNtlmPhase2BlockBase)); never executed (the execution status of this line is deduced): qt_noop(); | - |
1373 | if (data.size() < QNtlmPhase2BlockBase::Size) never evaluated: data.size() < QNtlmPhase2BlockBase::Size | 0 |
1374 | return false; never executed: return false; | 0 |
1375 | | - |
1376 | | - |
1377 | QDataStream ds(data); never executed (the execution status of this line is deduced): QDataStream ds(data); | - |
1378 | ds.setByteOrder(QDataStream::LittleEndian); never executed (the execution status of this line is deduced): ds.setByteOrder(QDataStream::LittleEndian); | - |
1379 | if (ds.readRawData(ch.magic, 8) < 8) never evaluated: ds.readRawData(ch.magic, 8) < 8 | 0 |
1380 | return false; never executed: return false; | 0 |
1381 | if (strncmp(ch.magic, "NTLMSSP", 8) != 0) never evaluated: strncmp(ch.magic, "NTLMSSP", 8) != 0 | 0 |
1382 | return false; never executed: return false; | 0 |
1383 | | - |
1384 | ds >> ch.type; never executed (the execution status of this line is deduced): ds >> ch.type; | - |
1385 | if (ch.type != 2) never evaluated: ch.type != 2 | 0 |
1386 | return false; never executed: return false; | 0 |
1387 | | - |
1388 | ds >> ch.targetName; never executed (the execution status of this line is deduced): ds >> ch.targetName; | - |
1389 | ds >> ch.flags; never executed (the execution status of this line is deduced): ds >> ch.flags; | - |
1390 | if (ds.readRawData((char *)ch.challenge, 8) < 8) never evaluated: ds.readRawData((char *)ch.challenge, 8) < 8 | 0 |
1391 | return false; never executed: return false; | 0 |
1392 | ds >> ch.context[0] >> ch.context[1]; never executed (the execution status of this line is deduced): ds >> ch.context[0] >> ch.context[1]; | - |
1393 | ds >> ch.targetInfo; never executed (the execution status of this line is deduced): ds >> ch.targetInfo; | - |
1394 | | - |
1395 | if (ch.targetName.len > 0) { never evaluated: ch.targetName.len > 0 | 0 |
1396 | if (ch.targetName.len + ch.targetName.offset >= (unsigned)data.size()) never evaluated: ch.targetName.len + ch.targetName.offset >= (unsigned)data.size() | 0 |
1397 | return false; never executed: return false; | 0 |
1398 | | - |
1399 | ch.targetNameStr = qStringFromUcs2Le(data.mid(ch.targetName.offset, ch.targetName.len)); never executed (the execution status of this line is deduced): ch.targetNameStr = qStringFromUcs2Le(data.mid(ch.targetName.offset, ch.targetName.len)); | - |
1400 | } | 0 |
1401 | | - |
1402 | if (ch.targetInfo.len > 0) { never evaluated: ch.targetInfo.len > 0 | 0 |
1403 | if (ch.targetInfo.len + ch.targetInfo.offset > (unsigned)data.size()) never evaluated: ch.targetInfo.len + ch.targetInfo.offset > (unsigned)data.size() | 0 |
1404 | return false; never executed: return false; | 0 |
1405 | | - |
1406 | ch.targetInfoBuff = data.mid(ch.targetInfo.offset, ch.targetInfo.len); never executed (the execution status of this line is deduced): ch.targetInfoBuff = data.mid(ch.targetInfo.offset, ch.targetInfo.len); | - |
1407 | } | 0 |
1408 | | - |
1409 | return true; never executed: return true; | 0 |
1410 | } | - |
1411 | | - |
1412 | | - |
1413 | static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data) | - |
1414 | { | - |
1415 | QNtlmPhase2Block ch; never executed (the execution status of this line is deduced): QNtlmPhase2Block ch; | - |
1416 | if (!qNtlmDecodePhase2(phase2data, ch)) never evaluated: !qNtlmDecodePhase2(phase2data, ch) | 0 |
1417 | return QByteArray(); never executed: return QByteArray(); | 0 |
1418 | | - |
1419 | QByteArray rc; never executed (the execution status of this line is deduced): QByteArray rc; | - |
1420 | QDataStream ds(&rc, QIODevice::WriteOnly); never executed (the execution status of this line is deduced): QDataStream ds(&rc, QIODevice::WriteOnly); | - |
1421 | ds.setByteOrder(QDataStream::LittleEndian); never executed (the execution status of this line is deduced): ds.setByteOrder(QDataStream::LittleEndian); | - |
1422 | QNtlmPhase3Block pb; never executed (the execution status of this line is deduced): QNtlmPhase3Block pb; | - |
1423 | | - |
1424 | bool unicode = ch.flags & NTLMSSP_NEGOTIATE_UNICODE; never executed (the execution status of this line is deduced): bool unicode = ch.flags & 0x00000001; | - |
1425 | | - |
1426 | pb.flags = NTLMSSP_NEGOTIATE_NTLM; never executed (the execution status of this line is deduced): pb.flags = 0x00000200; | - |
1427 | if (unicode) | 0 |
1428 | pb.flags |= NTLMSSP_NEGOTIATE_UNICODE; never executed: pb.flags |= 0x00000001; | 0 |
1429 | else | - |
1430 | pb.flags |= NTLMSSP_NEGOTIATE_OEM; never executed: pb.flags |= 0x00000002; | 0 |
1431 | | - |
1432 | | - |
1433 | int offset = QNtlmPhase3BlockBase::Size; never executed (the execution status of this line is deduced): int offset = QNtlmPhase3BlockBase::Size; | - |
1434 | Q_ASSERT(QNtlmPhase3BlockBase::Size == sizeof(QNtlmPhase3BlockBase)); never executed (the execution status of this line is deduced): qt_noop(); | - |
1435 | | - |
1436 | // for kerberos style user@domain logins, NTLM domain string should be left empty | - |
1437 | if (ctx->userDomain.isEmpty() && !ctx->extractedUser.contains(QLatin1Char('@'))) { never evaluated: ctx->userDomain.isEmpty() never evaluated: !ctx->extractedUser.contains(QLatin1Char('@')) | 0 |
1438 | offset = qEncodeNtlmString(pb.domain, offset, ch.targetNameStr, unicode); never executed (the execution status of this line is deduced): offset = qEncodeNtlmString(pb.domain, offset, ch.targetNameStr, unicode); | - |
1439 | pb.domainStr = ch.targetNameStr; never executed (the execution status of this line is deduced): pb.domainStr = ch.targetNameStr; | - |
1440 | } else { | 0 |
1441 | offset = qEncodeNtlmString(pb.domain, offset, ctx->userDomain, unicode); never executed (the execution status of this line is deduced): offset = qEncodeNtlmString(pb.domain, offset, ctx->userDomain, unicode); | - |
1442 | pb.domainStr = ctx->userDomain; never executed (the execution status of this line is deduced): pb.domainStr = ctx->userDomain; | - |
1443 | } | 0 |
1444 | | - |
1445 | offset = qEncodeNtlmString(pb.user, offset, ctx->extractedUser, unicode); never executed (the execution status of this line is deduced): offset = qEncodeNtlmString(pb.user, offset, ctx->extractedUser, unicode); | - |
1446 | pb.userStr = ctx->extractedUser; never executed (the execution status of this line is deduced): pb.userStr = ctx->extractedUser; | - |
1447 | | - |
1448 | offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode); never executed (the execution status of this line is deduced): offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode); | - |
1449 | pb.workstationStr = ctx->workstation; never executed (the execution status of this line is deduced): pb.workstationStr = ctx->workstation; | - |
1450 | | - |
1451 | // Get LM response | - |
1452 | #ifdef NTLMV1_CLIENT | - |
1453 | pb.lmResponseBuf = qEncodeLmResponse(ctx, ch); | - |
1454 | #else | - |
1455 | if (ch.targetInfo.len > 0) { never evaluated: ch.targetInfo.len > 0 | 0 |
1456 | pb.lmResponseBuf = QByteArray(); never executed (the execution status of this line is deduced): pb.lmResponseBuf = QByteArray(); | - |
1457 | } else { | 0 |
1458 | pb.lmResponseBuf = qEncodeLmv2Response(ctx, ch, &pb); never executed (the execution status of this line is deduced): pb.lmResponseBuf = qEncodeLmv2Response(ctx, ch, &pb); | - |
1459 | } | 0 |
1460 | #endif | - |
1461 | offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf); never executed (the execution status of this line is deduced): offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf); | - |
1462 | | - |
1463 | // Get NTLM response | - |
1464 | #ifdef NTLMV1_CLIENT | - |
1465 | pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch); | - |
1466 | #else | - |
1467 | pb.ntlmResponseBuf = qEncodeNtlmv2Response(ctx, ch, &pb); never executed (the execution status of this line is deduced): pb.ntlmResponseBuf = qEncodeNtlmv2Response(ctx, ch, &pb); | - |
1468 | #endif | - |
1469 | offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf); never executed (the execution status of this line is deduced): offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf); | - |
1470 | | - |
1471 | | - |
1472 | // Encode and send | - |
1473 | ds << pb; never executed (the execution status of this line is deduced): ds << pb; | - |
1474 | | - |
1475 | return rc; never executed: return rc; | 0 |
1476 | } | - |
1477 | | - |
1478 | #ifdef Q_OS_WIN | - |
1479 | // See http://davenport.sourceforge.net/ntlm.html | - |
1480 | // and libcurl http_ntlm.c | - |
1481 | | - |
1482 | // Handle of secur32.dll | - |
1483 | static HMODULE securityDLLHandle = NULL; | - |
1484 | // Pointer to SSPI dispatch table | - |
1485 | static PSecurityFunctionTable pSecurityFunctionTable = NULL; | - |
1486 | | - |
1487 | | - |
1488 | static bool q_NTLM_SSPI_library_load() | - |
1489 | { | - |
1490 | QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&pSecurityFunctionTable)); | - |
1491 | | - |
1492 | // Initialize security interface | - |
1493 | if (pSecurityFunctionTable == NULL) { | - |
1494 | securityDLLHandle = LoadLibrary(L"secur32.dll"); | - |
1495 | if (securityDLLHandle != NULL) { | - |
1496 | #if defined(Q_OS_WINCE) | - |
1497 | INIT_SECURITY_INTERFACE pInitSecurityInterface = | - |
1498 | (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle, | - |
1499 | L"InitSecurityInterfaceW"); | - |
1500 | #else | - |
1501 | INIT_SECURITY_INTERFACE pInitSecurityInterface = | - |
1502 | (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle, | - |
1503 | "InitSecurityInterfaceW"); | - |
1504 | #endif | - |
1505 | if (pInitSecurityInterface != NULL) | - |
1506 | pSecurityFunctionTable = pInitSecurityInterface(); | - |
1507 | } | - |
1508 | } | - |
1509 | | - |
1510 | if (pSecurityFunctionTable == NULL) | - |
1511 | return false; | - |
1512 | | - |
1513 | return true; | - |
1514 | } | - |
1515 | | - |
1516 | #ifdef Q_OS_WIN | - |
1517 | // Phase 1: | - |
1518 | static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx) | - |
1519 | { | - |
1520 | QByteArray result; | - |
1521 | | - |
1522 | if (!q_NTLM_SSPI_library_load()) | - |
1523 | return result; | - |
1524 | | - |
1525 | // 1. The client obtains a representation of the credential set | - |
1526 | // for the user via the SSPI AcquireCredentialsHandle function. | - |
1527 | if (!ctx->ntlmWindowsHandles) | - |
1528 | ctx->ntlmWindowsHandles = new QNtlmWindowsHandles; | - |
1529 | memset(&ctx->ntlmWindowsHandles->credHandle, 0, sizeof(CredHandle)); | - |
1530 | TimeStamp tsDummy; | - |
1531 | SECURITY_STATUS secStatus = pSecurityFunctionTable->AcquireCredentialsHandle( | - |
1532 | NULL, (SEC_WCHAR*)L"NTLM", SECPKG_CRED_OUTBOUND, NULL, NULL, | - |
1533 | NULL, NULL, &ctx->ntlmWindowsHandles->credHandle, &tsDummy); | - |
1534 | if (secStatus != SEC_E_OK) { | - |
1535 | delete ctx->ntlmWindowsHandles; | - |
1536 | ctx->ntlmWindowsHandles = 0; | - |
1537 | return result; | - |
1538 | } | - |
1539 | | - |
1540 | // 2. The client calls the SSPI InitializeSecurityContext function | - |
1541 | // to obtain an authentication request token (in our case, a Type 1 message). | - |
1542 | // The client sends this token to the server. | - |
1543 | SecBufferDesc desc; | - |
1544 | SecBuffer buf; | - |
1545 | desc.ulVersion = SECBUFFER_VERSION; | - |
1546 | desc.cBuffers = 1; | - |
1547 | desc.pBuffers = &buf; | - |
1548 | buf.cbBuffer = 0; | - |
1549 | buf.BufferType = SECBUFFER_TOKEN; | - |
1550 | buf.pvBuffer = NULL; | - |
1551 | ULONG attrs; | - |
1552 | | - |
1553 | secStatus = pSecurityFunctionTable->InitializeSecurityContext(&ctx->ntlmWindowsHandles->credHandle, NULL, | - |
1554 | const_cast<SEC_WCHAR*>(L"") /* host */, | - |
1555 | ISC_REQ_ALLOCATE_MEMORY, | - |
1556 | 0, SECURITY_NETWORK_DREP, | - |
1557 | NULL, 0, | - |
1558 | &ctx->ntlmWindowsHandles->ctxHandle, &desc, | - |
1559 | &attrs, &tsDummy); | - |
1560 | if (secStatus == SEC_I_COMPLETE_AND_CONTINUE || | - |
1561 | secStatus == SEC_I_CONTINUE_NEEDED) { | - |
1562 | pSecurityFunctionTable->CompleteAuthToken(&ctx->ntlmWindowsHandles->ctxHandle, &desc); | - |
1563 | } else if (secStatus != SEC_E_OK) { | - |
1564 | if ((const char*)buf.pvBuffer) | - |
1565 | pSecurityFunctionTable->FreeContextBuffer(buf.pvBuffer); | - |
1566 | pSecurityFunctionTable->FreeCredentialsHandle(&ctx->ntlmWindowsHandles->credHandle); | - |
1567 | delete ctx->ntlmWindowsHandles; | - |
1568 | ctx->ntlmWindowsHandles = 0; | - |
1569 | return result; | - |
1570 | } | - |
1571 | | - |
1572 | result = QByteArray((const char*)buf.pvBuffer, buf.cbBuffer); | - |
1573 | pSecurityFunctionTable->FreeContextBuffer(buf.pvBuffer); | - |
1574 | return result; | - |
1575 | } | - |
1576 | | - |
1577 | // Phase 2: | - |
1578 | // 3. The server receives the token from the client, and uses it as input to the | - |
1579 | // AcceptSecurityContext SSPI function. This creates a local security context on | - |
1580 | // the server to represent the client, and yields an authentication response token | - |
1581 | // (the Type 2 message), which is sent to the client. | - |
1582 | | - |
1583 | // Phase 3: | - |
1584 | static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data) | - |
1585 | { | - |
1586 | // 4. The client receives the response token from the server and calls | - |
1587 | // InitializeSecurityContext again, passing the server's token as input. | - |
1588 | // This provides us with another authentication request token (the Type 3 message). | - |
1589 | // The return value indicates that the security context was successfully initialized; | - |
1590 | // the token is sent to the server. | - |
1591 | | - |
1592 | QByteArray result; | - |
1593 | | - |
1594 | if (pSecurityFunctionTable == NULL) | - |
1595 | return result; | - |
1596 | | - |
1597 | SecBuffer type_2, type_3; | - |
1598 | SecBufferDesc type_2_desc, type_3_desc; | - |
1599 | ULONG attrs; | - |
1600 | TimeStamp tsDummy; // For Windows 9x compatibility of SPPI calls | - |
1601 | | - |
1602 | type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; | - |
1603 | type_2_desc.cBuffers = type_3_desc.cBuffers = 1; | - |
1604 | type_2_desc.pBuffers = &type_2; | - |
1605 | type_3_desc.pBuffers = &type_3; | - |
1606 | | - |
1607 | type_2.BufferType = SECBUFFER_TOKEN; | - |
1608 | type_2.pvBuffer = (PVOID)phase2data.data(); | - |
1609 | type_2.cbBuffer = phase2data.length(); | - |
1610 | type_3.BufferType = SECBUFFER_TOKEN; | - |
1611 | type_3.pvBuffer = 0; | - |
1612 | type_3.cbBuffer = 0; | - |
1613 | | - |
1614 | SECURITY_STATUS secStatus = pSecurityFunctionTable->InitializeSecurityContext(&ctx->ntlmWindowsHandles->credHandle, | - |
1615 | &ctx->ntlmWindowsHandles->ctxHandle, | - |
1616 | const_cast<SEC_WCHAR*>(L"") /* host */, | - |
1617 | ISC_REQ_ALLOCATE_MEMORY, | - |
1618 | 0, SECURITY_NETWORK_DREP, &type_2_desc, | - |
1619 | 0, &ctx->ntlmWindowsHandles->ctxHandle, &type_3_desc, | - |
1620 | &attrs, &tsDummy); | - |
1621 | | - |
1622 | if (secStatus == SEC_E_OK && ((const char*)type_3.pvBuffer)) { | - |
1623 | result = QByteArray((const char*)type_3.pvBuffer, type_3.cbBuffer); | - |
1624 | pSecurityFunctionTable->FreeContextBuffer(type_3.pvBuffer); | - |
1625 | } | - |
1626 | | - |
1627 | pSecurityFunctionTable->FreeCredentialsHandle(&ctx->ntlmWindowsHandles->credHandle); | - |
1628 | pSecurityFunctionTable->DeleteSecurityContext(&ctx->ntlmWindowsHandles->ctxHandle); | - |
1629 | delete ctx->ntlmWindowsHandles; | - |
1630 | ctx->ntlmWindowsHandles = 0; | - |
1631 | | - |
1632 | return result; | - |
1633 | } | - |
1634 | #endif // Q_OS_WIN | - |
1635 | | - |
1636 | #endif | - |
1637 | | - |
1638 | QT_END_NAMESPACE | - |
1639 | | - |
| | |