Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#include "controlinterface.h"
#include "usbauthorizationutils.h"

Check warning on line 7 in deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "usbauthorizationutils.h" not found.
#include "drivermanager.h"

Check warning on line 8 in deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "drivermanager.h" not found.
#include "modcore.h"

Check warning on line 9 in deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "modcore.h" not found.
#include "utils.h"

Check warning on line 10 in deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "utils.h" not found.
#include "debinstaller.h"
#include "enablesqlmanager.h"
#include "enableutils.h"
Expand Down Expand Up @@ -98,15 +99,10 @@
return ioctlEnableNetwork(hclass, name, path, value, enable_device, strDriver);
}

// 先从数据库中查找路径,防止设备更换usb接口
QString sPath = EnableSqlManager::getInstance()->authorizedPath(value);
sPath = path;

// 判断是内置设备,还是外设,内置设备通过remove文件禁用,外设通过authorized文件禁用
bool res = false;
if (QFile::exists("/sys" + sPath + QString("/authorized"))) {
modifyPath(sPath);
res = authorizedEnable(hclass, name, sPath, value, enable_device, strDriver);
if (QFile::exists("/sys" + path + QString("/authorized"))) {
res = authorizedEnable(hclass, name, path, value, enable_device, strDriver);
} else { /* if(QFile::exists("/sys" + sPath + QString("/remove")))*/
res = removeEnable(hclass, name, path, value, enable_device, strDriver);
}
Expand Down Expand Up @@ -332,42 +328,14 @@
#endif
bool ControlInterface::authorizedEnable(const QString &hclass, const QString &name, const QString &path, const QString &unique_id, bool enable_device, const QString strDriver)
{
// 通过authorized文件启用禁用设备
// 0:表示禁用 ,1:表示启用
QFile file("/sys" + path + QString("/authorized"));
if (!file.open(QIODevice::ReadWrite)) {
// A composite USB device may expose keyboard, mouse and control interfaces.
// Keep their authorization state consistent with the selected physical device.
if (!UsbAuthorizationUtils::setInterfacesAuthorized(path, enable_device))
return false;
}
if (enable_device) {
/*
启用的流程为:以 /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0 为例
第一步: 向 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/authorized 文件中写 1
第二步: 向 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-5/authorized 文件中写 0
第三步: 向 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-5/authorized 文件中写 1
*/
// 第一步
file.write("1");
file.close();

// 第二步
QFileInfo fi(path);
QString pop = fi.path();
QFile fpop("/sys" + pop + QString("/authorized"));
if (!fpop.open(QIODevice::ReadWrite))
return false;
fpop.write("0");
fpop.close();

// 第三步
if (!fpop.open(QIODevice::ReadWrite))
return false;
fpop.write("1");
fpop.close();

if (enable_device) {
EnableSqlManager::getInstance()->removeDataFromAuthorizedTable(unique_id);
} else {
file.write("0");
file.close();
EnableSqlManager::getInstance()->insertDataToAuthorizedTable(hclass, name, path, unique_id, true, strDriver);
}
return true;
Expand Down Expand Up @@ -473,11 +441,6 @@
*d = '\0';
}

void ControlInterface::modifyPath(QString &path)
{
path.replace(QRegExp("[1-9]$"), "0");
}

void ControlInterface::saveWakeupInfo(const QString &unique_id, const QString &path, bool wakeup)
{
if (EnableSqlManager::getInstance()->isWakeupUniqueIdExisted(unique_id)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 ~ 2023 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019-2026 ~ 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

Expand Down Expand Up @@ -184,13 +184,6 @@ public slots:
* @param value
*/
void construct_uri(char *buffer, size_t buflen, const char *base, const char *value);
/**
* @brief modifyPath 修正路径 保证xxx.0
* 比如将 /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1
* 修正为 /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0
* @param path 需要修正的路径 /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0
*/
void modifyPath(QString &path);
/**
* @brief saveWakeupInfo 保存数据到数据库
* @param unique_id 唯一标识
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include "enableutils.h"
#include "enablesqlmanager.h"
#include "usbauthorizationutils.h"

#include <QStringList>

Check warning on line 9 in deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QStringList> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMap>

Check warning on line 10 in deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMap> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFile>
#include <QDir>
#include <QProcess>
Expand Down Expand Up @@ -117,9 +118,6 @@
} else {
path = mapItem["SysFS ID"];
}
path.replace(QRegExp("[1-9]$"), "0");


// 网卡采用ioctl的方式禁用(链路二:开机/服务唤起时恢复禁用状态)
QRegExp reg(REG_ADDRESS);
if (reg.exactMatch(uniqueID)) {
Expand All @@ -133,12 +131,8 @@

// 先判断设备是否被记录在数据库,如果在则禁用
if (EnableSqlManager::getInstance()->uniqueIDExisted(uniqueID)) {
QFile file("/sys" + path + QString("/authorized"));
if (!file.open(QIODevice::ReadWrite)) {
return;
}
file.write("0");
file.close();
if (!UsbAuthorizationUtils::setInterfacesAuthorized(path, false))
continue;
// 更数据库信息,方式更换usb接口
EnableSqlManager::getInstance()->updateDataToAuthorizedTable(uniqueID, path);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "usbauthorizationutils.h"

#include <QDir>

Check warning on line 7 in deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/usbauthorizationutils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDir> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDebug>

Check warning on line 8 in deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/usbauthorizationutils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFile>

Check warning on line 9 in deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/usbauthorizationutils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFile> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFileInfo>

Check warning on line 10 in deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/usbauthorizationutils.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFileInfo> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QRegularExpression>

namespace {

QString physicalDevicePath(const QString &path, const QString &sysRoot)
{
if (!path.startsWith("/devices/") || path.contains(".."))
return {};

const QFileInfo pathInfo(path);
const QString pathName = pathInfo.fileName();
static const QRegularExpression interfacePattern("^(.+):[0-9]+\\.[0-9]+$");
static const QRegularExpression devicePattern("^[0-9]+-[0-9]+(?:\\.[0-9]+)*$");
const QRegularExpressionMatch interfaceMatch = interfacePattern.match(pathName);

QString deviceName;
QString devicePath;
if (interfaceMatch.hasMatch()) {
deviceName = interfaceMatch.captured(1);
devicePath = pathInfo.path();
if (QFileInfo(devicePath).fileName() != deviceName)
return {};
} else {
deviceName = pathName;
devicePath = path;
if (!devicePattern.match(deviceName).hasMatch())
return {};
}

return QDir(sysRoot + devicePath).exists() ? devicePath : QString();
}

bool readAuthorized(const QString &filePath, bool &authorized)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to read USB authorized file" << filePath << file.errorString();
return false;
}

const QByteArray value = file.readAll().trimmed();
if (value != "0" && value != "1") {
qWarning() << "Invalid USB authorized value" << filePath << value;
return false;
}

authorized = value == "1";
return true;
}

bool writeAuthorized(const QString &filePath, bool authorized)
{
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "Failed to open USB authorized file" << filePath << file.errorString();
return false;
}

const QByteArray value = authorized ? "1" : "0";
if (file.write(value) != value.size()) {
qWarning() << "Failed to write USB authorized file" << filePath << file.errorString();
return false;
}

return true;
}

} // namespace

QStringList UsbAuthorizationUtils::interfacePaths(const QString &path, const QString &sysRoot)
{
const QString devicePath = physicalDevicePath(path, sysRoot);
if (devicePath.isEmpty())
return {};

const QString deviceName = QFileInfo(devicePath).fileName();
QDir deviceDir(sysRoot + devicePath);
const QRegularExpression siblingPattern(QString("^%1:[0-9]+\\.[0-9]+$")
.arg(QRegularExpression::escape(deviceName)));
QStringList interfaces;
const QFileInfoList entries = deviceDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
for (const QFileInfo &entry : entries) {
if (!siblingPattern.match(entry.fileName()).hasMatch())
continue;

const QString interfacePath = devicePath + '/' + entry.fileName();
if (QFileInfo::exists(sysRoot + interfacePath + "/authorized"))
interfaces.append(interfacePath);
}

return interfaces;
}

bool UsbAuthorizationUtils::setInterfacesAuthorized(const QString &path, bool authorized, const QString &sysRoot)
{
const QString devicePath = physicalDevicePath(path, sysRoot);
const QStringList interfaces = interfacePaths(path, sysRoot);
if (devicePath.isEmpty() || interfaces.isEmpty()) {
qWarning() << "No USB interfaces found for" << path;
return false;
}

QList<QPair<QString, bool>> originalStates;
for (const QString &interfacePath : interfaces) {
const QString authorizedPath = sysRoot + interfacePath + "/authorized";
bool originalState = false;
if (!readAuthorized(authorizedPath, originalState))
return false;
originalStates.append(qMakePair(interfacePath, originalState));
}

bool originalDeviceState = false;
const QString deviceAuthorizedPath = sysRoot + devicePath + "/authorized";
if (authorized && !readAuthorized(deviceAuthorizedPath, originalDeviceState))
return false;

int changedCount = 0;
const auto rollbackInterfaces = [&originalStates, &sysRoot, &changedCount]() {
bool restored = true;
for (int index = changedCount - 1; index >= 0; --index) {
const QPair<QString, bool> &state = originalStates.at(index);
if (!writeAuthorized(sysRoot + state.first + "/authorized", state.second)) {
qCritical() << "Failed to roll back USB interface" << state.first;
restored = false;
}
}
return restored;
};

for (const QString &interfacePath : interfaces) {
if (!writeAuthorized(sysRoot + interfacePath + "/authorized", authorized)) {
if (!rollbackInterfaces())
qCritical() << "USB interface rollback incomplete for" << path;
return false;
}
++changedCount;
}

if (authorized
&& (!writeAuthorized(deviceAuthorizedPath, false)
|| !writeAuthorized(deviceAuthorizedPath, true))) {
const bool deviceRestored = writeAuthorized(deviceAuthorizedPath, originalDeviceState);
const bool interfacesRestored = rollbackInterfaces();
if (!deviceRestored || !interfacesRestored)
qCritical() << "USB device rollback incomplete for" << devicePath;
return false;
}

qInfo() << "Set USB interfaces authorized" << authorized << path << interfaces;
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef USBAUTHORIZATIONUTILS_H
#define USBAUTHORIZATIONUTILS_H

#include <QString>
#include <QStringList>

class UsbAuthorizationUtils
{
public:
/**
* @brief Return all authorized-capable interfaces of a physical USB device.
* @param path USB device or interface path below /devices.
* @param sysRoot Sysfs root, overridden by tests.
*/
static QStringList interfacePaths(const QString &path, const QString &sysRoot = "/sys");
/**
* @brief Set all interfaces to the same authorization state.
* @param path USB device or interface path below /devices.
* @param authorized Whether the interfaces should be authorized.
* @param sysRoot Sysfs root, overridden by tests.
*/
static bool setInterfacesAuthorized(const QString &path, bool authorized, const QString &sysRoot = "/sys");
};

#endif // USBAUTHORIZATIONUTILS_H
Loading