summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2022-11-07 11:09:06 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-11-08 14:04:42 +0000
commitc28ad246d13f7755b154936265419140505c7e2e (patch)
tree37577d0862c1e7f33f4a908bbc481b0c0e4d94c7
parent1c0652da289d9e425b37d7ea9f52771f21c46794 (diff)
downloadqtbase-c28ad246d13f7755b154936265419140505c7e2e.tar.gz
getProxyAuth: stop using deprecated API
A new SDK marked several functions in SecKeychain family as deprecated. Fortunately for us, Security framework on the whole is not deprecated and thus provides an alternative API to inspect keychain items, and also much nicer one - instead of having a function with 15 parameters, those parameters are 'collapsed' into one, the 'query', which is a dictionary. Fixes: QTBUG-108196 Change-Id: I602d1a846ff9683cac724859a776de2b901f5c1c Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io> (cherry picked from commit 02b9033d50def3b4c70a4f0504b5894d4249be1b) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp106
1 files changed, 64 insertions, 42 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index df1be89947..435dec190c 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -45,12 +45,15 @@
#include <QHostInfo>
#include "QtCore/qapplicationstatic.h"
+#include "QtCore/qloggingcategory.h"
#include <QtCore/private/qfactoryloader_p.h>
#if defined(Q_OS_MACOS)
+#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreServices/CoreServices.h>
#include <SystemConfiguration/SystemConfiguration.h>
-#include <Security/SecKeychain.h>
+#include <Security/Security.h>
#endif
#ifdef Q_OS_WASM
#include "qnetworkreplywasmimpl_p.h"
@@ -66,6 +69,8 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+Q_LOGGING_CATEGORY(lcQnam, "qt.network.access.manager")
+
Q_APPLICATION_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
#ifdef QT_BUILD_INTERNAL
@@ -77,55 +82,72 @@ Q_APPLICATION_STATIC(QFactoryLoader, loader, QNetworkAccessBackendFactory_iid, "
#if defined(Q_OS_MACOS)
bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password)
{
- OSStatus err;
- SecKeychainItemRef itemRef;
- bool retValue = false;
- SecProtocolType protocolType = kSecProtocolTypeAny;
+ CFStringRef protocolType = nullptr;
if (scheme.compare("ftp"_L1, Qt::CaseInsensitive) == 0) {
- protocolType = kSecProtocolTypeFTPProxy;
+ protocolType = kSecAttrProtocolFTPProxy;
} else if (scheme.compare("http"_L1, Qt::CaseInsensitive) == 0
|| scheme.compare("preconnect-http"_L1, Qt::CaseInsensitive) == 0) {
- protocolType = kSecProtocolTypeHTTPProxy;
+ protocolType = kSecAttrProtocolHTTPProxy;
} else if (scheme.compare("https"_L1,Qt::CaseInsensitive)==0
|| scheme.compare("preconnect-https"_L1, Qt::CaseInsensitive) == 0) {
- protocolType = kSecProtocolTypeHTTPSProxy;
+ protocolType = kSecAttrProtocolHTTPSProxy;
+ } else {
+ qCWarning(lcQnam) << "Cannot query user name and password for a proxy, unnknown protocol:"
+ << scheme;
+ return false;
}
- QByteArray proxyHostnameUtf8(proxyHostname.toUtf8());
- err = SecKeychainFindInternetPassword(NULL,
- proxyHostnameUtf8.length(), proxyHostnameUtf8.constData(),
- 0,NULL,
- 0, NULL,
- 0, NULL,
- 0,
- protocolType,
- kSecAuthenticationTypeAny,
- 0, NULL,
- &itemRef);
- if (err == noErr) {
-
- SecKeychainAttribute attr;
- SecKeychainAttributeList attrList;
- UInt32 length;
- void *outData;
-
- attr.tag = kSecAccountItemAttr;
- attr.length = 0;
- attr.data = NULL;
-
- attrList.count = 1;
- attrList.attr = &attr;
-
- if (SecKeychainItemCopyContent(itemRef, NULL, &attrList, &length, &outData) == noErr) {
- username = QString::fromUtf8((const char*)attr.data, attr.length);
- password = QString::fromUtf8((const char*)outData, length);
- SecKeychainItemFreeContent(&attrList,outData);
- retValue = true;
- }
- CFRelease(itemRef);
+
+ QCFType<CFMutableDictionaryRef> query(CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0, nullptr, nullptr));
+ Q_ASSERT(query);
+
+ CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
+ CFDictionaryAddValue(query, kSecAttrProtocol, protocolType);
+
+ QCFType<CFStringRef> serverName; // Note the scope.
+ if (proxyHostname.size()) {
+ serverName = proxyHostname.toCFString();
+ CFDictionaryAddValue(query, kSecAttrServer, serverName);
+ }
+
+ // This is to get the user name in the result:
+ CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
+ // This one to get the password:
+ CFDictionaryAddValue(query, kSecReturnData, kCFBooleanTrue);
+
+ // The default for kSecMatchLimit key is 1 (the first match only), which is fine,
+ // so don't set this value explicitly.
+
+ QCFType<CFTypeRef> replyData;
+ if (SecItemCopyMatching(query, &replyData) != errSecSuccess) {
+ qCWarning(lcQnam, "Failed to extract user name and password from the keychain.");
+ return false;
}
- return retValue;
+
+ if (!replyData || CFDictionaryGetTypeID() != CFGetTypeID(replyData)) {
+ qCWarning(lcQnam, "Query returned data in unexpected format.");
+ return false;
+ }
+
+ CFDictionaryRef accountData = replyData.as<CFDictionaryRef>();
+ const void *value = CFDictionaryGetValue(accountData, kSecAttrAccount);
+ if (!value || CFGetTypeID(value) != CFStringGetTypeID()) {
+ qCWarning(lcQnam, "Cannot find user name or its format is unknown.");
+ return false;
+ }
+ username = QString::fromCFString(static_cast<CFStringRef>(value));
+
+ value = CFDictionaryGetValue(accountData, kSecValueData);
+ if (!value || CFGetTypeID(value) != CFDataGetTypeID()) {
+ qCWarning(lcQnam, "Cannot find password or its format is unknown.");
+ return false;
+ }
+ const CFDataRef passData = static_cast<const CFDataRef>(value);
+ password = QString::fromLocal8Bit(reinterpret_cast<const char *>(CFDataGetBytePtr(passData)),
+ qsizetype(CFDataGetLength(passData)));
+ return true;
}
-#endif
+#endif // Q_OS_MACOS