mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 07:55:21 +01:00
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:
parent
ebaf2ef6a1
commit
6dc2f3e58e
12 changed files with 373 additions and 197 deletions
|
@ -12,8 +12,8 @@ OPTION (ENABLE_TELEMETRY "Enable sending telemetry" ON)
|
|||
project(rpi-imager LANGUAGES CXX C)
|
||||
set(IMAGER_VERSION_MAJOR 1)
|
||||
set(IMAGER_VERSION_MINOR 7)
|
||||
set(IMAGER_VERSION_STR "${IMAGER_VERSION_MAJOR}.${IMAGER_VERSION_MINOR}.4")
|
||||
set(IMAGER_VERSION_CSV "${IMAGER_VERSION_MAJOR},${IMAGER_VERSION_MINOR},4,0")
|
||||
set(IMAGER_VERSION_STR "${IMAGER_VERSION_MAJOR}.${IMAGER_VERSION_MINOR}.4.1")
|
||||
set(IMAGER_VERSION_CSV "${IMAGER_VERSION_MAJOR},${IMAGER_VERSION_MINOR},4,1")
|
||||
add_definitions(-DIMAGER_VERSION_STR="${IMAGER_VERSION_STR}")
|
||||
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
|
||||
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)
|
||||
|
||||
# Add dependencies
|
||||
if (APPLE)
|
||||
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
|
||||
mac/macwlancredentials.h mac/macwlancredentials.cpp
|
||||
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
||||
enable_language(OBJC C)
|
||||
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)
|
||||
if(Qt5DBus_FOUND)
|
||||
set(DEPENDENCIES ${DEPENDENCIES} linux/udisks2api.cpp linux/udisks2api.h
|
||||
linux/networkmanagerapi.h linux/networkmanagerapi.cpp)
|
||||
set(DEPENDENCIES ${DEPENDENCIES} linux/udisks2api.cpp linux/udisks2api.h)
|
||||
set(EXTRALIBS Qt5::DBus)
|
||||
message("udisks2 support enabled")
|
||||
else()
|
||||
|
@ -62,7 +62,7 @@ elseif (UNIX)
|
|||
endif()
|
||||
elseif (WIN32)
|
||||
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)
|
||||
find_package(Qt5WinExtras REQUIRED)
|
||||
set(EXTRALIBS setupapi wlanapi Qt5::WinExtras)
|
||||
|
|
|
@ -499,7 +499,7 @@ Popup {
|
|||
fieldWifiCountry.currentIndex = fieldWifiCountry.find("GB")
|
||||
fieldWifiSSID.text = imageWriter.getSSID()
|
||||
if (fieldWifiSSID.text.length) {
|
||||
fieldWifiPassword.text = imageWriter.getPSK(fieldWifiSSID.text)
|
||||
fieldWifiPassword.text = imageWriter.getPSK()
|
||||
if (fieldWifiPassword.text.length) {
|
||||
chkShowPassword.checked = false
|
||||
if (Qt.platform.os == "osx") {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "driveformatthread.h"
|
||||
#include "localfileextractthread.h"
|
||||
#include "downloadstatstelemetry.h"
|
||||
#include "wlancredentials.h"
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <random>
|
||||
|
@ -38,17 +39,10 @@
|
|||
#endif
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <QMessageBox>
|
||||
#include <security/security.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#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 <QWinTaskbarProgress>
|
||||
#endif
|
||||
|
@ -57,12 +51,6 @@
|
|||
#include <QtPlatformHeaders/QEglFSFunctions>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#ifndef QT_NO_DBUS
|
||||
#include "linux/networkmanagerapi.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ImageWriter::ImageWriter(QObject *parent)
|
||||
: QObject(parent), _repo(QUrl(QString(OSLIST_URL))), _dlnow(0), _verifynow(0),
|
||||
_engine(nullptr), _thread(nullptr), _verifyEnabled(false), _cachingEnabled(false),
|
||||
|
@ -863,173 +851,23 @@ QStringList ImageWriter::getKeymapLayoutList()
|
|||
|
||||
QString ImageWriter::getSSID()
|
||||
{
|
||||
/* Qt used to have proper bearer management that was able to provide a list of
|
||||
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;
|
||||
return WlanCredentials::instance()->getSSID();
|
||||
}
|
||||
|
||||
inline QString unescapeXml(QString str)
|
||||
QString ImageWriter::getPSK()
|
||||
{
|
||||
static const char *table[] = {
|
||||
"<", "<",
|
||||
">", ">",
|
||||
""", "\"",
|
||||
"'", "'",
|
||||
"&", "&"
|
||||
};
|
||||
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
|
||||
SecKeychainRef keychainRef;
|
||||
QString psk;
|
||||
QByteArray ssidAscii = ssid.toLatin1();
|
||||
|
||||
/* On OSX the user is presented with a prompt for the admin password when opening the system key chain.
|
||||
* Ask if user wants to obtain the wlan password first to make sure this is desired and
|
||||
* to provide the user with context. */
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
#endif
|
||||
|
||||
return psk;
|
||||
#else
|
||||
#ifndef QT_NO_DBUS
|
||||
NetworkManagerApi nm;
|
||||
return nm.getPSK();
|
||||
#else
|
||||
Q_UNUSED(ssid)
|
||||
return QString();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
return WlanCredentials::instance()->getPSK();
|
||||
}
|
||||
|
||||
bool ImageWriter::getBoolSetting(const QString &key)
|
||||
|
|
|
@ -103,7 +103,7 @@ public:
|
|||
Q_INVOKABLE QStringList getCountryList();
|
||||
Q_INVOKABLE QStringList getKeymapLayoutList();
|
||||
Q_INVOKABLE QString getSSID();
|
||||
Q_INVOKABLE QString getPSK(const QString &ssid);
|
||||
Q_INVOKABLE QString getPSK();
|
||||
|
||||
Q_INVOKABLE bool getBoolSetting(const QString &key);
|
||||
Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);
|
||||
|
|
|
@ -4,30 +4,76 @@
|
|||
*/
|
||||
|
||||
#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 <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
typedef QMap<QString, QVariantMap> VariantMapMap;
|
||||
Q_DECLARE_METATYPE(VariantMapMap)
|
||||
|
||||
NetworkManagerApi::NetworkManagerApi(QObject *parent)
|
||||
: QObject{parent}
|
||||
NetworkManagerApi::NetworkManagerApi()
|
||||
{
|
||||
|
||||
#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",
|
||||
"org.freedesktop.NetworkManager", QDBusConnection::systemBus());
|
||||
|
||||
if (!nm.isValid())
|
||||
{
|
||||
qDebug() << "NetworkManager not available";
|
||||
return QString();
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
const auto activeConnections = nm.property("ActiveConnections").value<QList<QDBusObjectPath>>();
|
||||
|
@ -52,8 +98,18 @@ QString NetworkManagerApi::getPSK()
|
|||
continue;
|
||||
QVariantMap secrets = reply.value().value("802-11-wireless-security");
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
* Copyright (C) 2022 Raspberry Pi Ltd
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
#include "wlancredentials.h"
|
||||
|
||||
class NetworkManagerApi : public QObject
|
||||
class NetworkManagerApi : public WlanCredentials
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NetworkManagerApi(QObject *parent = nullptr);
|
||||
QString getPSK();
|
||||
|
||||
signals:
|
||||
NetworkManagerApi();
|
||||
virtual QByteArray getSSID();
|
||||
virtual QByteArray getPSK();
|
||||
|
||||
protected:
|
||||
QByteArray _getSSIDofInterface(const QByteArray &iface);
|
||||
};
|
||||
|
||||
#endif // NETWORKMANAGERAPI_H
|
||||
|
|
73
src/mac/macwlancredentials.cpp
Normal file
73
src/mac/macwlancredentials.cpp
Normal 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;
|
||||
}
|
||||
|
21
src/mac/macwlancredentials.h
Normal file
21
src/mac/macwlancredentials.h
Normal 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
|
140
src/windows/winwlancredentials.cpp
Normal file
140
src/windows/winwlancredentials.cpp
Normal 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[] = {
|
||||
"<", "<",
|
||||
">", ">",
|
||||
""", "\"",
|
||||
"'", "'",
|
||||
"&", "&"
|
||||
};
|
||||
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;
|
||||
}
|
22
src/windows/winwlancredentials.h
Normal file
22
src/windows/winwlancredentials.h
Normal 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
0
src/wlancredentials.cpp
Normal file
26
src/wlancredentials.h
Normal file
26
src/wlancredentials.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue