Refactor WLAN PSK retrieval code

- Reduce platform specific code in ImageWriter class,
  and move that to seperate classes.
- Use API calls to get current SSID on Windows and Linux instead
  of launching command line utilities.
This commit is contained in:
Floris Bos 2023-03-10 18:37:22 +01:00
parent ebaf2ef6a1
commit 6dc2f3e58e
12 changed files with 373 additions and 197 deletions

View file

@ -12,8 +12,8 @@ OPTION (ENABLE_TELEMETRY "Enable sending telemetry" ON)
project(rpi-imager LANGUAGES CXX C) project(rpi-imager LANGUAGES CXX C)
set(IMAGER_VERSION_MAJOR 1) set(IMAGER_VERSION_MAJOR 1)
set(IMAGER_VERSION_MINOR 7) set(IMAGER_VERSION_MINOR 7)
set(IMAGER_VERSION_STR "${IMAGER_VERSION_MAJOR}.${IMAGER_VERSION_MINOR}.4") set(IMAGER_VERSION_STR "${IMAGER_VERSION_MAJOR}.${IMAGER_VERSION_MINOR}.4.1")
set(IMAGER_VERSION_CSV "${IMAGER_VERSION_MAJOR},${IMAGER_VERSION_MINOR},4,0") set(IMAGER_VERSION_CSV "${IMAGER_VERSION_MAJOR},${IMAGER_VERSION_MINOR},4,1")
add_definitions(-DIMAGER_VERSION_STR="${IMAGER_VERSION_STR}") add_definitions(-DIMAGER_VERSION_STR="${IMAGER_VERSION_STR}")
add_definitions(-DIMAGER_VERSION_CSV=${IMAGER_VERSION_CSV}) add_definitions(-DIMAGER_VERSION_CSV=${IMAGER_VERSION_CSV})
@ -23,21 +23,21 @@ set(CMAKE_AUTORCC ON)
# Adding headers explicity so they are displayed in Qt Creator # Adding headers explicity so they are displayed in Qt Creator
set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h drivelistmodelpollthread.h driveformatthread.h powersaveblocker.h cli.h set(HEADERS config.h imagewriter.h networkaccessmanagerfactory.h nan.h drivelistitem.h drivelistmodel.h drivelistmodelpollthread.h driveformatthread.h powersaveblocker.h cli.h
devicewrapper.h devicewrapperblockcacheentry.h devicewrapperpartition.h devicewrapperstructs.h devicewrapperfatpartition.h devicewrapper.h devicewrapperblockcacheentry.h devicewrapperpartition.h devicewrapperstructs.h devicewrapperfatpartition.h wlancredentials.h
downloadthread.h downloadextractthread.h localfileextractthread.h downloadstatstelemetry.h dependencies/mountutils/src/mountutils.hpp dependencies/sha256crypt/sha256crypt.h) downloadthread.h downloadextractthread.h localfileextractthread.h downloadstatstelemetry.h dependencies/mountutils/src/mountutils.hpp dependencies/sha256crypt/sha256crypt.h)
# Add dependencies # Add dependencies
if (APPLE) if (APPLE)
set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") set_source_files_properties("icons/rpi-imager.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
set(DEPENDENCIES acceleratedcryptographichash.cpp mac/macfile.cpp mac/macfile.h dependencies/mountutils/src/darwin/functions.cpp set(DEPENDENCIES acceleratedcryptographichash.cpp mac/macfile.cpp mac/macfile.h dependencies/mountutils/src/darwin/functions.cpp
mac/macwlancredentials.h mac/macwlancredentials.cpp
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns) dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
enable_language(OBJC C) enable_language(OBJC C)
elseif (UNIX) elseif (UNIX)
set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp) set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp linux/networkmanagerapi.h linux/networkmanagerapi.cpp)
find_package(Qt5DBus) find_package(Qt5DBus)
if(Qt5DBus_FOUND) if(Qt5DBus_FOUND)
set(DEPENDENCIES ${DEPENDENCIES} linux/udisks2api.cpp linux/udisks2api.h set(DEPENDENCIES ${DEPENDENCIES} linux/udisks2api.cpp linux/udisks2api.h)
linux/networkmanagerapi.h linux/networkmanagerapi.cpp)
set(EXTRALIBS Qt5::DBus) set(EXTRALIBS Qt5::DBus)
message("udisks2 support enabled") message("udisks2 support enabled")
else() else()
@ -62,7 +62,7 @@ elseif (UNIX)
endif() endif()
elseif (WIN32) elseif (WIN32)
set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp set(DEPENDENCIES acceleratedcryptographichash.cpp dependencies/mountutils/src/windows/functions.cpp dependencies/drivelist/src/windows/list.cpp
windows/winfile.cpp windows/winfile.h windows/winfile.cpp windows/winfile.h windows/winwlancredentials.h windows/winwlancredentials.cpp
windows/rpi-imager.rc) windows/rpi-imager.rc)
find_package(Qt5WinExtras REQUIRED) find_package(Qt5WinExtras REQUIRED)
set(EXTRALIBS setupapi wlanapi Qt5::WinExtras) set(EXTRALIBS setupapi wlanapi Qt5::WinExtras)

View file

@ -499,7 +499,7 @@ Popup {
fieldWifiCountry.currentIndex = fieldWifiCountry.find("GB") fieldWifiCountry.currentIndex = fieldWifiCountry.find("GB")
fieldWifiSSID.text = imageWriter.getSSID() fieldWifiSSID.text = imageWriter.getSSID()
if (fieldWifiSSID.text.length) { if (fieldWifiSSID.text.length) {
fieldWifiPassword.text = imageWriter.getPSK(fieldWifiSSID.text) fieldWifiPassword.text = imageWriter.getPSK()
if (fieldWifiPassword.text.length) { if (fieldWifiPassword.text.length) {
chkShowPassword.checked = false chkShowPassword.checked = false
if (Qt.platform.os == "osx") { if (Qt.platform.os == "osx") {

View file

@ -11,6 +11,7 @@
#include "driveformatthread.h" #include "driveformatthread.h"
#include "localfileextractthread.h" #include "localfileextractthread.h"
#include "downloadstatstelemetry.h" #include "downloadstatstelemetry.h"
#include "wlancredentials.h"
#include <archive.h> #include <archive.h>
#include <archive_entry.h> #include <archive_entry.h>
#include <random> #include <random>
@ -38,17 +39,10 @@
#endif #endif
#ifdef Q_OS_DARWIN #ifdef Q_OS_DARWIN
#include <QMessageBox> #include <QMessageBox>
#include <security/security.h>
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <windows.h> #include <windows.h>
#include <winioctl.h>
#include <wlanapi.h>
#ifndef WLAN_PROFILE_GET_PLAINTEXT_KEY
#define WLAN_PROFILE_GET_PLAINTEXT_KEY 4
#endif
#include <QWinTaskbarButton> #include <QWinTaskbarButton>
#include <QWinTaskbarProgress> #include <QWinTaskbarProgress>
#endif #endif
@ -57,12 +51,6 @@
#include <QtPlatformHeaders/QEglFSFunctions> #include <QtPlatformHeaders/QEglFSFunctions>
#endif #endif
#ifdef Q_OS_LINUX
#ifndef QT_NO_DBUS
#include "linux/networkmanagerapi.h"
#endif
#endif
ImageWriter::ImageWriter(QObject *parent) ImageWriter::ImageWriter(QObject *parent)
: QObject(parent), _repo(QUrl(QString(OSLIST_URL))), _dlnow(0), _verifynow(0), : QObject(parent), _repo(QUrl(QString(OSLIST_URL))), _dlnow(0), _verifynow(0),
_engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false), _engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false),
@ -863,173 +851,23 @@ QStringList ImageWriter::getKeymapLayoutList()
QString ImageWriter::getSSID() QString ImageWriter::getSSID()
{ {
/* Qt used to have proper bearer management that was able to provide a list of return WlanCredentials::instance()->getSSID();
SSIDs, but since they retired it, resort to calling platform specific tools for now.
Minimal implementation that only gets the currently connected SSID */
QString program, regexpstr, ssid;
QStringList args;
QProcess proc;
#ifdef Q_OS_WIN
program = "netsh";
args << "wlan" << "show" << "interfaces";
regexpstr = "[ \t]+SSID[ \t]*: (.+)";
#else
#ifdef Q_OS_DARWIN
program = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport";
args << "-I";
regexpstr = "[ \t]+SSID: (.+)";
#else
program = "iwgetid";
args << "-r";
#endif
#endif
proc.start(program, args);
if (proc.waitForStarted(2000) && proc.waitForFinished(2000))
{
if (regexpstr.isEmpty())
{
ssid = proc.readAll().trimmed();
}
else
{
QRegularExpression rx(regexpstr);
const QList<QByteArray> outputlines = proc.readAll().replace('\r', "").split('\n');
for (const QByteArray &line : outputlines) {
QRegularExpressionMatch match = rx.match(line);
if (match.hasMatch())
{
ssid = match.captured(1);
break;
}
}
}
}
return ssid;
} }
inline QString unescapeXml(QString str) QString ImageWriter::getPSK()
{ {
static const char *table[] = {
"&lt;", "<",
"&gt;", ">",
"&quot;", "\"",
"&apos;", "'",
"&amp;", "&"
};
int tableLen = sizeof(table) / sizeof(table[0]);
for (int i=0; i < tableLen; i+=2)
{
str.replace(table[i], table[i+1]);
}
return str;
}
QString ImageWriter::getPSK(const QString &ssid)
{
#ifdef Q_OS_WIN
/* Windows allows retrieving wifi PSK */
HANDLE h;
DWORD ret = 0;
DWORD supportedVersion = 0;
DWORD clientVersion = 2;
QString psk;
if (WlanOpenHandle(clientVersion, NULL, &supportedVersion, &h) != ERROR_SUCCESS)
return QString();
PWLAN_INTERFACE_INFO_LIST ifList = NULL;
if (WlanEnumInterfaces(h, NULL, &ifList) == ERROR_SUCCESS)
{
for (int i=0; i < ifList->dwNumberOfItems; i++)
{
PWLAN_PROFILE_INFO_LIST profileList = NULL;
if (WlanGetProfileList(h, &ifList->InterfaceInfo[i].InterfaceGuid,
NULL, &profileList) == ERROR_SUCCESS)
{
for (int j=0; j < profileList->dwNumberOfItems; j++)
{
QString s = QString::fromWCharArray(profileList->ProfileInfo[j].strProfileName);
qDebug() << "Enumerating wifi profiles, SSID found:" << s << " looking for:" << ssid;
if (s == ssid) {
DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY;
DWORD access = 0;
DWORD ret = 0;
LPWSTR xmlstr = NULL;
if ( (ret = WlanGetProfile(h, &ifList->InterfaceInfo[i].InterfaceGuid, profileList->ProfileInfo[j].strProfileName,
NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr)
{
QString xml = QString::fromWCharArray(xmlstr);
qDebug() << "XML wifi profile:" << xml;
QRegularExpression rx("<keyMaterial>(.+)</keyMaterial>");
QRegularExpressionMatch match = rx.match(xml);
if (match.hasMatch()) {
psk = unescapeXml(match.captured(1));
}
WlanFreeMemory(xmlstr);
break;
}
}
}
}
if (profileList) {
WlanFreeMemory(profileList);
}
}
}
if (ifList)
WlanFreeMemory(ifList);
WlanCloseHandle(h, NULL);
return psk;
#else
#ifdef Q_OS_DARWIN #ifdef Q_OS_DARWIN
SecKeychainRef keychainRef; /* On OSX the user is presented with a prompt for the admin password when opening the system key chain.
QString psk; * Ask if user wants to obtain the wlan password first to make sure this is desired and
QByteArray ssidAscii = ssid.toLatin1(); * to provide the user with context. */
if (QMessageBox::question(nullptr, "", if (QMessageBox::question(nullptr, "",
tr("Would you like to prefill the wifi password from the system keychain?")) == QMessageBox::Yes) tr("Would you like to prefill the wifi password from the system keychain?")) != QMessageBox::Yes)
{ {
if (SecKeychainOpen("/Library/Keychains/System.keychain", &keychainRef) == errSecSuccess) return QString();
{
UInt32 resultLen;
void *result;
if (SecKeychainFindGenericPassword(keychainRef, 0, NULL, ssidAscii.length(), ssidAscii.constData(), &resultLen, &result, NULL) == errSecSuccess)
{
psk = QByteArray((char *) result, resultLen);
SecKeychainItemFreeContent(NULL, result);
}
CFRelease(keychainRef);
}
} }
#endif
return psk; return WlanCredentials::instance()->getPSK();
#else
#ifndef QT_NO_DBUS
NetworkManagerApi nm;
return nm.getPSK();
#else
Q_UNUSED(ssid)
return QString();
#endif
#endif
#endif
} }
bool ImageWriter::getBoolSetting(const QString &key) bool ImageWriter::getBoolSetting(const QString &key)

View file

@ -103,7 +103,7 @@ public:
Q_INVOKABLE QStringList getCountryList(); Q_INVOKABLE QStringList getCountryList();
Q_INVOKABLE QStringList getKeymapLayoutList(); Q_INVOKABLE QStringList getKeymapLayoutList();
Q_INVOKABLE QString getSSID(); Q_INVOKABLE QString getSSID();
Q_INVOKABLE QString getPSK(const QString &ssid); Q_INVOKABLE QString getPSK();
Q_INVOKABLE bool getBoolSetting(const QString &key); Q_INVOKABLE bool getBoolSetting(const QString &key);
Q_INVOKABLE void setSetting(const QString &key, const QVariant &value); Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);

View file

@ -4,30 +4,76 @@
*/ */
#include "networkmanagerapi.h" #include "networkmanagerapi.h"
#include <QDebug>
#include <QNetworkInterface>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/wireless.h>
#ifndef QT_NO_DBUS
#include <QDBusMetaType> #include <QDBusMetaType>
#include <QDBusInterface> #include <QDBusInterface>
#include <QDBusReply> #include <QDBusReply>
#include <QDebug> #endif
typedef QMap<QString, QVariantMap> VariantMapMap; typedef QMap<QString, QVariantMap> VariantMapMap;
Q_DECLARE_METATYPE(VariantMapMap) Q_DECLARE_METATYPE(VariantMapMap)
NetworkManagerApi::NetworkManagerApi(QObject *parent) NetworkManagerApi::NetworkManagerApi()
: QObject{parent}
{ {
#ifndef QT_NO_DBUS
qDBusRegisterMetaType<VariantMapMap>();
#endif
} }
QString NetworkManagerApi::getPSK() QByteArray NetworkManagerApi::getSSID()
{ {
qDBusRegisterMetaType<VariantMapMap>(); QByteArray ssid;
const auto interfaces = QNetworkInterface::allInterfaces();
for (const auto &interface : interfaces)
{
if (interface.type() == interface.Wifi)
{
ssid = _getSSIDofInterface(interface.name().toLatin1());
if (!ssid.isEmpty())
break;
}
}
return ssid;
}
QByteArray NetworkManagerApi::_getSSIDofInterface(const QByteArray &iface)
{
char ssid[IW_ESSID_MAX_SIZE+1] = {0};
struct iwreq iw = {0};
int s = ::socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
return QByteArray();
strncpy(iw.ifr_ifrn.ifrn_name, iface.data(), sizeof(iw.ifr_ifrn.ifrn_name));
iw.u.essid.pointer = ssid;
iw.u.essid.length = IW_ESSID_MAX_SIZE;
::ioctl(s, SIOCGIWESSID, &iw);
::close(s);
return QByteArray(ssid);
}
QByteArray NetworkManagerApi::getPSK()
{
#ifndef QT_NO_DBUS
QDBusInterface nm("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", QDBusInterface nm("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",
"org.freedesktop.NetworkManager", QDBusConnection::systemBus()); "org.freedesktop.NetworkManager", QDBusConnection::systemBus());
if (!nm.isValid()) if (!nm.isValid())
{ {
qDebug() << "NetworkManager not available"; qDebug() << "NetworkManager not available";
return QString(); return QByteArray();
} }
const auto activeConnections = nm.property("ActiveConnections").value<QList<QDBusObjectPath>>(); const auto activeConnections = nm.property("ActiveConnections").value<QList<QDBusObjectPath>>();
@ -52,8 +98,18 @@ QString NetworkManagerApi::getPSK()
continue; continue;
QVariantMap secrets = reply.value().value("802-11-wireless-security"); QVariantMap secrets = reply.value().value("802-11-wireless-security");
if (secrets.contains("psk")) if (secrets.contains("psk"))
return secrets.value("psk").toString(); return secrets.value("psk").toByteArray();
} }
#endif
return QString(); return QByteArray();
}
WlanCredentials *WlanCredentials::_instance = NULL;
WlanCredentials *WlanCredentials::instance()
{
if (!_instance)
_instance = new NetworkManagerApi();
return _instance;
} }

View file

@ -6,17 +6,17 @@
* Copyright (C) 2022 Raspberry Pi Ltd * Copyright (C) 2022 Raspberry Pi Ltd
*/ */
#include <QObject> #include "wlancredentials.h"
class NetworkManagerApi : public QObject class NetworkManagerApi : public WlanCredentials
{ {
Q_OBJECT
public: public:
explicit NetworkManagerApi(QObject *parent = nullptr); NetworkManagerApi();
QString getPSK(); virtual QByteArray getSSID();
virtual QByteArray getPSK();
signals:
protected:
QByteArray _getSSIDofInterface(const QByteArray &iface);
}; };
#endif // NETWORKMANAGERAPI_H #endif // NETWORKMANAGERAPI_H

View file

@ -0,0 +1,73 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2023 Raspberry Pi Ltd
*/
#include "macwlancredentials.h"
#include <security/security.h>
#include <QProcess>
#include <QRegularExpression>
QByteArray MacWlanCredentials::getSSID()
{
/* FIXME: find out the proper API call to get SSID instead of calling command line utilities */
QString program, regexpstr;
QStringList args;
QProcess proc;
program = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport";
args << "-I";
regexpstr = "[ \t]+SSID: (.+)";
proc.start(program, args);
if (proc.waitForStarted(2000) && proc.waitForFinished(2000))
{
QRegularExpression rx(regexpstr);
const QList<QByteArray> outputlines = proc.readAll().replace('\r', "").split('\n');
for (const QByteArray &line : outputlines) {
QRegularExpressionMatch match = rx.match(line);
if (match.hasMatch())
{
_ssid = match.captured(1).toLatin1();
break;
}
}
}
return _ssid;
}
QByteArray MacWlanCredentials::getPSK()
{
SecKeychainRef keychainRef;
QByteArray psk;
if (_ssid.isEmpty())
getSSID();
if (_ssid.isEmpty())
return psk;
if (SecKeychainOpen("/Library/Keychains/System.keychain", &keychainRef) == errSecSuccess)
{
UInt32 resultLen;
void *result;
if (SecKeychainFindGenericPassword(keychainRef, 0, NULL, _ssid.length(), _ssid.constData(), &resultLen, &result, NULL) == errSecSuccess)
{
psk = QByteArray((char *) result, resultLen);
SecKeychainItemFreeContent(NULL, result);
}
CFRelease(keychainRef);
}
return psk;
}
WlanCredentials *WlanCredentials::_instance = NULL;
WlanCredentials *WlanCredentials::instance()
{
if (!_instance)
_instance = new MacWlanCredentials();
return _instance;
}

View file

@ -0,0 +1,21 @@
#ifndef MACWLANCREDENTIALS_H
#define MACWLANCREDENTIALS_H
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2023 Raspberry Pi Ltd
*/
#include "wlancredentials.h"
class MacWlanCredentials : public WlanCredentials
{
public:
virtual QByteArray getSSID();
virtual QByteArray getPSK();
protected:
QByteArray _ssid;
};
#endif // MACWLANCREDENTIALS_H

View file

@ -0,0 +1,140 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2023 Raspberry Pi Ltd
*/
#include "winwlancredentials.h"
#include <windows.h>
#include <winioctl.h>
#include <wlanapi.h>
#include <Windot11.h>
#include <QDebug>
#include <QRegularExpression>
#ifndef WLAN_PROFILE_GET_PLAINTEXT_KEY
#define WLAN_PROFILE_GET_PLAINTEXT_KEY 4
#endif
inline QString unescapeXml(QString str)
{
static const char *table[] = {
"&lt;", "<",
"&gt;", ">",
"&quot;", "\"",
"&apos;", "'",
"&amp;", "&"
};
int tableLen = sizeof(table) / sizeof(table[0]);
for (int i=0; i < tableLen; i+=2)
{
str.replace(table[i], table[i+1]);
}
return str;
}
WinWlanCredentials::WinWlanCredentials()
{
/* Get both SSID and PSK in one go, and store it in variables */
HANDLE h;
DWORD supportedVersion = 0;
DWORD clientVersion = 2;
if (WlanOpenHandle(clientVersion, NULL, &supportedVersion, &h) != ERROR_SUCCESS)
return;
PWLAN_INTERFACE_INFO_LIST ifList = NULL;
if (WlanEnumInterfaces(h, NULL, &ifList) == ERROR_SUCCESS)
{
for (DWORD i=0; i < ifList->dwNumberOfItems; i++)
{
PWLAN_PROFILE_INFO_LIST profileList = NULL;
if (ifList->InterfaceInfo[i].isState != wlan_interface_state_connected)
continue; /* Wlan adapter not connected */
/* Get current connection info for SSID */
PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
if (WlanQueryInterface(h, &ifList->InterfaceInfo[i].InterfaceGuid,
wlan_intf_opcode_current_connection, NULL,
&connectInfoSize, (PVOID *) &pConnectInfo, &opCode) != ERROR_SUCCESS || !pConnectInfo)
{
continue;
}
if (pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength)
{
_ssid = QByteArray((const char *) pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID,
pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength);
}
WlanFreeMemory(pConnectInfo);
if (_ssid.isEmpty())
continue;
if (WlanGetProfileList(h, &ifList->InterfaceInfo[i].InterfaceGuid,
NULL, &profileList) == ERROR_SUCCESS)
{
for (DWORD j=0; j < profileList->dwNumberOfItems; j++)
{
QString s = QString::fromWCharArray(profileList->ProfileInfo[j].strProfileName);
qDebug() << "Enumerating wlan profiles, SSID found:" << s << " looking for:" << _ssid;
if (s == _ssid) {
DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY;
DWORD access = 0;
DWORD ret = 0;
LPWSTR xmlstr = NULL;
if ( (ret = WlanGetProfile(h, &ifList->InterfaceInfo[i].InterfaceGuid, profileList->ProfileInfo[j].strProfileName,
NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr)
{
QString xml = QString::fromWCharArray(xmlstr);
qDebug() << "XML wlan profile:" << xml;
QRegularExpression rx("<keyMaterial>(.+)</keyMaterial>");
QRegularExpressionMatch match = rx.match(xml);
if (match.hasMatch()) {
_psk = unescapeXml(match.captured(1)).toLatin1();
}
WlanFreeMemory(xmlstr);
break;
}
}
}
}
if (profileList) {
WlanFreeMemory(profileList);
}
}
}
if (ifList)
WlanFreeMemory(ifList);
WlanCloseHandle(h, NULL);
}
QByteArray WinWlanCredentials::getSSID()
{
return _ssid;
}
QByteArray WinWlanCredentials::getPSK()
{
return _psk;
}
WlanCredentials *WlanCredentials::_instance = NULL;
WlanCredentials *WlanCredentials::instance()
{
if (!_instance)
_instance = new WinWlanCredentials();
return _instance;
}

View file

@ -0,0 +1,22 @@
#ifndef WINWLANCREDENTIALS_H
#define WINWLANCREDENTIALS_H
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2023 Raspberry Pi Ltd
*/
#include "wlancredentials.h"
class WinWlanCredentials : public WlanCredentials
{
public:
WinWlanCredentials();
virtual QByteArray getSSID();
virtual QByteArray getPSK();
protected:
QByteArray _ssid, _psk;
};
#endif // WINWLANCREDENTIALS_H

0
src/wlancredentials.cpp Normal file
View file

26
src/wlancredentials.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef WLANCREDENTIALS_H
#define WLANCREDENTIALS_H
/*
* Interface for wlan credential detection
* Use WlanCredentials::instance() to get platform
* specific implementation
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2023 Raspberry Pi Ltd
*/
#include <QByteArray>
class WlanCredentials
{
public:
static WlanCredentials *instance();
virtual QByteArray getSSID() = 0;
virtual QByteArray getPSK() = 0;
protected:
static WlanCredentials *_instance;
};
#endif // WLANCREDENTIALS_H