From e0918af700acefd6e80562c051e42d0b64097e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 7 Sep 2020 18:15:14 +0200 Subject: QAuthenticator: condition using GSSAPI on credentials availability AFAICT with GSSAPI the normal workflow is to run kinit or similar and authenticate before running programs relying on it. Therefore we can try to get the credentials before we choose whether or not to use Negotiate. Pick-to: 5.15 Task-number: QTBUG-85123 Change-Id: If0478fdd45389b2939ad87c2f582776fe56959bb Reviewed-by: Timur Pocheptsov --- src/network/kernel/qauthenticator.cpp | 66 +++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 11 deletions(-) (limited to 'src/network/kernel/qauthenticator.cpp') diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index c23e82dd85..3db7161add 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -81,6 +81,7 @@ static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method, const QString& host, const QByteArray& challenge = QByteArray()); #elif QT_CONFIG(gssapi) // GSSAPI +static bool qGssapiTestGetCredentials(const QString &host); static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString& host); static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray& challenge = QByteArray()); @@ -422,7 +423,7 @@ void QAuthenticatorPrivate::updateCredentials() } } -void QAuthenticatorPrivate::parseHttpResponse(const QList > &values, bool isProxy) +void QAuthenticatorPrivate::parseHttpResponse(const QList > &values, bool isProxy, const QString &host) { const char *search = isProxy ? "proxy-authenticate" : "www-authenticate"; @@ -454,6 +455,13 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList(serviceName.size()), serviceName.data()}; + + gss_name_t importedName; + OM_uint32 minStat; + OM_uint32 majStat = gss_import_name(&minStat, &nameDesc, + GSS_C_NT_HOSTBASED_SERVICE, &importedName); + + if (majStat != GSS_S_COMPLETE) { + q_GSSAPI_error("gss_import_name error", majStat, minStat); + return nullptr; + } + return importedName; +} + // Send initial GSS authentication token static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString &host) { - OM_uint32 majStat, minStat; - if (!ctx->gssApiHandles) ctx->gssApiHandles.reset(new QGssApiHandles); // Convert target name to internal form - QByteArray serviceName = QStringLiteral("HTTPS@%1").arg(host).toLocal8Bit(); - gss_buffer_desc nameDesc = {static_cast(serviceName.size()), serviceName.data()}; - - majStat = gss_import_name(&minStat, &nameDesc, - GSS_C_NT_HOSTBASED_SERVICE, &ctx->gssApiHandles->targetName); - - if (majStat != GSS_S_COMPLETE) { - q_GSSAPI_error("gss_import_name error", majStat, minStat); + gss_name_t name = qGSsapiGetServiceName(host); + if (name == nullptr) { ctx->gssApiHandles.reset(nullptr); return QByteArray(); } + ctx->gssApiHandles->targetName = name; // Call qGssapiContinue with GSS_C_NO_CONTEXT to get initial packet ctx->gssApiHandles->gssCtx = GSS_C_NO_CONTEXT; @@ -1750,6 +1772,28 @@ static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray& return result; } +static bool qGssapiTestGetCredentials(const QString &host) +{ + gss_name_t serviceName = qGSsapiGetServiceName(host); + if (!serviceName) + return false; // Something was wrong with the service name, so skip this + OM_uint32 minStat; + gss_cred_id_t cred; + OM_uint32 majStat = gss_acquire_cred(&minStat, serviceName, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_INITIATE, &cred, nullptr, + nullptr); + + OM_uint32 ignored; + gss_release_name(&ignored, &serviceName); + gss_release_cred(&ignored, &cred); + + if (majStat != GSS_S_COMPLETE) { + q_GSSAPI_error("gss_acquire_cred", majStat, minStat); + return false; + } + return true; +} + // ---------------------------- End of GSSAPI code ---------------------------------------------- #endif // gssapi -- cgit v1.2.3