From b53c229a4b394e6b83268151845e1fee734f633d Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sat, 14 Jan 2017 12:22:53 +0900 Subject: Fix build without features.networkinterface Change-Id: I9fd2a7ec402a1d2d99e30f08554d86f18c6424ff Reviewed-by: Paul Olav Tvete --- src/network/socket/qnativesocketengine_p.h | 4 ++++ src/network/socket/qnativesocketengine_unix.cpp | 2 ++ 2 files changed, 6 insertions(+) (limited to 'src/network') diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 4d1d8e1eb1..08e72072ef 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -286,8 +286,10 @@ public: bool checkProxy(const QHostAddress &address); bool fetchConnectionParameters(); +#if QT_CONFIG(networkinterface) static uint scopeIdFromString(const QString &scopeid) { return QNetworkInterface::interfaceIndexFromName(scopeid); } +#endif /*! \internal Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize. @@ -301,7 +303,9 @@ public: || socketProtocol == QAbstractSocket::AnyIPProtocol) { memset(&aa->a6, 0, sizeof(sockaddr_in6)); aa->a6.sin6_family = AF_INET6; +#if QT_CONFIG(networkinterface) aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId()); +#endif aa->a6.sin6_port = htons(port); Q_IPV6ADDR tmp = address.toIPv6Address(); memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp)); diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index e140b33ce9..09c06adb1e 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -121,8 +121,10 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po QHostAddress tmpAddress; tmpAddress.setAddress(tmp); *addr = tmpAddress; +#if QT_CONFIG(networkinterface) if (s->a6.sin6_scope_id) addr->setScopeId(QNetworkInterface::interfaceNameFromIndex(s->a6.sin6_scope_id)); +#endif } if (port) *port = ntohs(s->a6.sin6_port); -- cgit v1.2.3 From 5377f4ec0e82dbfbd0d148ed3affc0c7b2a3cade Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 1 Feb 2017 13:55:32 +0100 Subject: Allow Secure Transport backend to use a temporary keychain Cherry picked: this change was first merged into dev, but now we also need it in 5.9 to enable SSL socket tests on the new CI VMs (macOS 10.11, 10.12). As we do not merge dev->5.9, we need this cherry-pick. Since day one Secure Transport socket has two annoying problems on macOS: when we call SecPKCS12Import, we indeed import certs and keys into the default keychain and also (which is more serious) later a dialog can pop up, asking for permission to use a private key (this is especially annoying if you're running SSL autotests or have a server application). Apparently, it's possible to work around those problems if we create our own (temporary) keychain and pass it in the 'options' parameter to SecPKCS12Import. [ChangeLog][QtNetwork] Allow QSslSocket to use a temporary keychain on macOS. Task-number: QTBUG-56102 Change-Id: Ic3a56c905100dc80d907a25fe6ebfa232dcf5b9e Reviewed-by: Edward Welbourne (cherry picked from commit 17927392cf1cecb20cef7cb9cd77131391de087c) Reviewed-by: Timur Pocheptsov --- src/network/ssl/qsslsocket.cpp | 7 +++ src/network/ssl/qsslsocket_mac.cpp | 124 +++++++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 6 deletions(-) (limited to 'src/network') diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index e655f4becd..84b8f3a8d9 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -972,6 +972,13 @@ QList QSslSocket::localCertificateChain() const sockets, but are also rarely used by client sockets if the server requires the client to authenticate. + \note Secure Transport SSL backend on macOS may update the default keychain + (the default is probably your login keychain) by importing your local certificates + and keys. This can also result in system dialogs showing up and asking for + permission when your application is using these private keys. If such behavior + is undesired, set the QT_SSL_USE_TEMPORARY_KEYCHAIN environment variable to a + non-zero value; this will prompt QSslSocket to use its own temporary keychain. + \sa localCertificate(), setPrivateKey() */ void QSslSocket::setLocalCertificate(const QSslCertificate &certificate) diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp index 3e56eac803..a2dee75895 100644 --- a/src/network/ssl/qsslsocket_mac.cpp +++ b/src/network/ssl/qsslsocket_mac.cpp @@ -53,9 +53,12 @@ #include #include #include +#include +#include #include #include +#include #include @@ -65,6 +68,102 @@ QT_BEGIN_NAMESPACE +namespace +{ +#ifdef Q_OS_MACOS +/* + +Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes +the default keychain and where we see annoying pop-ups asking about accessing a +private key. + +*/ + +struct EphemeralSecKeychain +{ + EphemeralSecKeychain(); + ~EphemeralSecKeychain(); + + SecKeychainRef keychain = nullptr; + Q_DISABLE_COPY(EphemeralSecKeychain) +}; + +EphemeralSecKeychain::EphemeralSecKeychain() +{ + const auto uuid = QUuid::createUuid(); + if (uuid.isNull()) { + qCWarning(lcSsl) << "Failed to create an unique keychain name"; + return; + } + + QString uuidAsString(uuid.toString()); + Q_ASSERT(uuidAsString.size() > 2); + Q_ASSERT(uuidAsString.startsWith(QLatin1Char('{')) + && uuidAsString.endsWith(QLatin1Char('}'))); + uuidAsString = uuidAsString.mid(1, uuidAsString.size() - 2); + + QString keychainName(QDir::tempPath()); + keychainName.append(QDir::separator()); + keychainName += uuidAsString; + keychainName += QLatin1String(".keychain"); + // SecKeychainCreate, pathName parameter: + // + // "A constant character string representing the POSIX path indicating where + // to store the keychain." + // + // Internally they seem to use std::string, but this does not really help. + // Fortunately, CFString has a convenient API. + QCFType cfName = keychainName.toCFString(); + std::vector posixPath; + // "Extracts the contents of a string as a NULL-terminated 8-bit string + // appropriate for passing to POSIX APIs." + posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName)); + const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0], + CFIndex(posixPath.size())); + if (!ok) { + qCWarning(lcSsl) << "Failed to create a unique keychain name from" + << "QDir::tempPath()"; + return; + } + + std::vector passUtf8(256); + if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) { + qCWarning(lcSsl) << "SecRandomCopyBytes: failed to create a key"; + return; + } + + const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(), + &passUtf8[0], FALSE, nullptr, + &keychain); + if (status != errSecSuccess || !keychain) { + qCWarning(lcSsl) << "SecKeychainCreate: failed to create a custom keychain"; + if (keychain) { + SecKeychainDelete(keychain); + CFRelease(keychain); + keychain = nullptr; + } + } + +#ifdef QSSLSOCKET_DEBUG + if (keychain) { + qCDebug(lcSsl) << "Custom keychain with name" << keychainName << "was created" + << "successfully"; + } +#endif +} + +EphemeralSecKeychain::~EphemeralSecKeychain() +{ + if (keychain) { + // clear file off disk + SecKeychainDelete(keychain); + CFRelease(keychain); + } +} + +#endif // Q_OS_MACOS +} + static SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode) { const bool isServer = mode == QSslSocket::SslServerMode; @@ -815,11 +914,24 @@ bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription, QCFType pkcs12 = _q_makePkcs12(configuration.localCertificateChain, configuration.privateKey, passPhrase).toCFData(); QCFType password = passPhrase.toCFString(); - const void *keys[] = { kSecImportExportPassphrase }; - const void *values[] = { password }; - QCFType options(CFDictionaryCreate(Q_NULLPTR, keys, values, 1, - Q_NULLPTR, Q_NULLPTR)); - CFArrayRef items = Q_NULLPTR; + const void *keys[2] = { kSecImportExportPassphrase }; + const void *values[2] = { password }; + CFIndex nKeys = 1; +#ifdef Q_OS_MACOS + bool envOk = false; + const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk); + if (envOk && env) { + static const EphemeralSecKeychain temporaryKeychain; + if (temporaryKeychain.keychain) { + nKeys = 2; + keys[1] = kSecImportExportKeychain; + values[1] = temporaryKeychain.keychain; + } + } +#endif + QCFType options = CFDictionaryCreate(nullptr, keys, values, nKeys, + nullptr, nullptr); + CFArrayRef items = nullptr; OSStatus err = SecPKCS12Import(pkcs12, options, &items); if (err != noErr) { #ifdef QSSLSOCKET_DEBUG @@ -851,7 +963,7 @@ bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription, return false; } - QCFType certs = CFArrayCreateMutable(Q_NULLPTR, 0, &kCFTypeArrayCallBacks); + QCFType certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); if (!certs) { errorCode = QAbstractSocket::SslInternalError; errorDescription = QStringLiteral("Failed to allocate certificates array"); -- cgit v1.2.3 From ce2771c71c6679a020ae66ac6602e04621a66a8f Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 4 Apr 2017 13:58:24 +0200 Subject: QNetworkRequest - do not set ManualRedirectPolicy If QNAM's general policy is 'Manual' and QNetworkRequest has neither policy set not FollowRedirectAttribute - do NOT set this 'Manual' policy - its implicitly implied. This fixes previously unnoticed auto test failure (was blacklisted) and also makes QNetworkRequest::operator == work correctly. Change-Id: If17c9af4baf8a470659f82d1a40488078ea8ede0 Reviewed-by: Edward Welbourne Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkaccessmanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/network') diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 0a6270d417..018586f9dc 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1280,11 +1280,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera Q_D(QNetworkAccessManager); QNetworkRequest req(originalReq); - if (req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull() + if (redirectPolicy() != QNetworkRequest::ManualRedirectPolicy + && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull() && req.attribute(QNetworkRequest::FollowRedirectsAttribute).isNull()) { - // We only apply the general manager's policy if: - // - RedirectPolicyAttribute is not set already on request and - // - no FollowRedirectsAttribute is set. req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy()); } -- cgit v1.2.3 From 71649e21680ce3d5194a6b7dfc92bd5ac67966ba Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 1 Apr 2017 11:19:22 -0700 Subject: Fix build when SCTP is enabled c0157a9f035a27a3ba20cab0ca3ca1c6e78f0b14 was incomplete. Change-Id: I27b55fdf514247549455fffd14b158f54403663d Reviewed-by: Timur Pocheptsov Reviewed-by: Edward Welbourne --- src/network/socket/qnativesocketengine.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/network') diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index cf3afe1845..b796934199 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -129,6 +129,10 @@ # include "qtcpserver.h" #endif +#if !defined(QT_NO_SCTP) +# include "qsctpserver.h" +#endif + QT_BEGIN_NAMESPACE //#define QNATIVESOCKETENGINE_DEBUG -- cgit v1.2.3 From 264d814773a15806df497e872e4b19c613c94725 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 2 Apr 2017 09:46:21 -0700 Subject: Fix GCC warning about dereferencing type-punned pointers GCC is wrong. Type-punning is when you read something of a given type as something else. We're not doing that, as it's only read as integer. qnativesocketengine_unix.cpp:1011:79: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing] Too bad my plan for a good C++ solution was foiled by glibc developers. Change-Id: I27b55fdf514247549455fffd14b1a27667745e94 Reviewed-by: Edward Welbourne --- src/network/socket/qnativesocketengine_unix.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/network') diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 09c06adb1e..3cf65b3553 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -987,7 +987,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int)) && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) { - header->hopLimit = *reinterpret_cast(CMSG_DATA(cmsgptr)); + Q_STATIC_ASSERT(sizeof(header->hopLimit) == sizeof(int)); + memcpy(&header->hopLimit, CMSG_DATA(cmsgptr), sizeof(header->hopLimit)); } #ifndef QT_NO_SCTP -- cgit v1.2.3