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)
|
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)
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
|
@ -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[] = {
|
|
||||||
"<", "<",
|
|
||||||
">", ">",
|
|
||||||
""", "\"",
|
|
||||||
"'", "'",
|
|
||||||
"&", "&"
|
|
||||||
};
|
|
||||||
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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
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