QAuthenticator: Fix crash when using NTLM / Negotiate
With NTLM/Negotiate we delete the context used to generate replies once we get SEC_E_OK. Due to some faulty logic in the http backend we could end up trying to generate another response. Qt would then pass references to some offsets of nullptr into the API calls causing it to crash. Add some sanity checks before the "sspi continue" calls to make sure this won't happen, and update the condition in the http backend to check that we have not already sent our credentials. As a drive-by: correct the initialization of the handles to use SecInvalidateHandle instead of memset to 0. Pick-to: 6.4 6.3 6.2 5.15 Fixes: QTBUG-102359 Change-Id: I884ff8fc70609fe8746b99a1d56eeafcda9d2620 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
90ad4d10ef
commit
c684b8e939
@ -570,9 +570,15 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
|
||||
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
|
||||
// Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
|
||||
if (priv && priv->method != QAuthenticatorPrivate::None) {
|
||||
if ((priv->method != QAuthenticatorPrivate::Ntlm
|
||||
&& request.headerField("Authorization").isEmpty())
|
||||
|| channel.lastStatus == 401) {
|
||||
const bool ntlmNego = priv->method == QAuthenticatorPrivate::Ntlm
|
||||
|| priv->method == QAuthenticatorPrivate::Negotiate;
|
||||
const bool authNeeded = channel.lastStatus == 401;
|
||||
const bool ntlmNegoOk = ntlmNego && authNeeded
|
||||
&& (priv->phase != QAuthenticatorPrivate::Done
|
||||
|| !channel.authenticationCredentialsSent);
|
||||
const bool otherOk =
|
||||
!ntlmNego && (authNeeded || request.headerField("Authorization").isEmpty());
|
||||
if (ntlmNegoOk || otherOk) {
|
||||
QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false),
|
||||
request.url().host());
|
||||
request.setHeaderField("Authorization", response);
|
||||
@ -585,7 +591,13 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
|
||||
priv = QAuthenticatorPrivate::getPrivate(*authenticator);
|
||||
// Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated.
|
||||
if (priv && priv->method != QAuthenticatorPrivate::None) {
|
||||
if (priv->method != QAuthenticatorPrivate::Ntlm || channel.lastStatus == 407) {
|
||||
const bool ntlmNego = priv->method == QAuthenticatorPrivate::Ntlm
|
||||
|| priv->method == QAuthenticatorPrivate::Negotiate;
|
||||
const bool proxyAuthNeeded = channel.lastStatus == 407;
|
||||
const bool ntlmNegoOk = ntlmNego && proxyAuthNeeded
|
||||
&& (priv->phase != QAuthenticatorPrivate::Done || !channel.proxyCredentialsSent);
|
||||
const bool otherOk = !ntlmNego;
|
||||
if (ntlmNegoOk || otherOk) {
|
||||
QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false),
|
||||
networkProxy.hostName());
|
||||
request.setHeaderField("Proxy-Authorization", response);
|
||||
|
@ -626,9 +626,11 @@ QByteArray QAuthenticatorPrivate::calculateResponse(QByteArrayView requestMethod
|
||||
} else {
|
||||
QByteArray phase3Token;
|
||||
#if QT_CONFIG(sspi) // SSPI
|
||||
phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge));
|
||||
if (sspiWindowsHandles)
|
||||
phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge));
|
||||
#elif QT_CONFIG(gssapi) // GSSAPI
|
||||
phase3Token = qGssapiContinue(this, QByteArray::fromBase64(challenge));
|
||||
if (gssApiHandles)
|
||||
phase3Token = qGssapiContinue(this, QByteArray::fromBase64(challenge));
|
||||
#endif
|
||||
if (!phase3Token.isEmpty()) {
|
||||
response = phase3Token.toBase64();
|
||||
@ -1583,7 +1585,8 @@ static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate
|
||||
|
||||
if (!ctx->sspiWindowsHandles)
|
||||
ctx->sspiWindowsHandles.reset(new QSSPIWindowsHandles);
|
||||
memset(&ctx->sspiWindowsHandles->credHandle, 0, sizeof(CredHandle));
|
||||
SecInvalidateHandle(&ctx->sspiWindowsHandles->credHandle);
|
||||
SecInvalidateHandle(&ctx->sspiWindowsHandles->ctxHandle);
|
||||
|
||||
SEC_WINNT_AUTH_IDENTITY auth;
|
||||
auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||||
|
Loading…
Reference in New Issue
Block a user