diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp b/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp index 4c4b7d34..596b1534 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include @@ -204,6 +206,93 @@ bool ControlInterface::enablePrinter(const QString &hclass, const QString &name, return true; } +bool ControlInterface::enableKeyboard(const QString& vid, const QString& pid, const QString &hclass, const QString &name, const QString &sPath, const QString &value, bool enable_device, const QString strDriver) +{ + qCInfo(appLog) << "Enable keyboard request:" << hclass << name << sPath << value << "enable:" << enable_device; + + if (!getUserAuthorPasswd()) { + qCWarning(appLog) << "Authorization failed for keyboard enable operation"; + return false; + } + + // Use EnableUtils's validation function + QString safeVid, safePid; + if (!EnableUtils::validateAndNormalizeVidPid(vid, pid, safeVid, safePid)) { + qCWarning(appLog) << "VID or PID validation failed. VID:" << vid << "PID:" << pid; + return false; + } + + QString rulesFile = QString(UDEV_RULES_PATH_LOCAL "/99-keyboard-device-control-%1-%2.rules").arg(vid).arg(pid); + + QString ruleContent; + if (enable_device) { + ruleContent = QString("# enable keyboard - VID:%1 PID:%2\n" + "ACTION==\"add|change\", SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%1\", ATTRS{idProduct}==\"%2\", " + "ATTR{authorized}=\"1\"").arg(safeVid, safePid); + qCInfo(appLog) << "Creating rule to enable keyboard"; + } else { + ruleContent = QString("# disable keyboard - VID:%1 PID:%2\n" + "ACTION==\"add|change\", SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%1\", ATTRS{idProduct}==\"%2\", " + "ATTR{authorized}=\"0\"").arg(safeVid, safePid); + qCInfo(appLog) << "Creating rule to disable keyboard"; + } + + QFileInfo fileInfo(rulesFile); + QDir rulesDir = fileInfo.absoluteDir(); + if (!rulesDir.exists()) { + qCWarning(appLog) << "Udev rules directory does not exist:" << rulesDir.absolutePath(); + return false; + } + + QFile file(rulesFile); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qCWarning(appLog) << "Failed to open udev rules file for writing:" << rulesFile; + qCWarning(appLog) << "Error:" << file.errorString(); + return false; + } + + QTextStream out(&file); + out << ruleContent; + file.close(); + + if (file.error() != QFile::NoError) { + qCWarning(appLog) << "Failed to write udev rule. Error:" << file.errorString(); + return false; + } + + QProcess reloadProcess; + qCInfo(appLog) << "Reloading udev rules"; + reloadProcess.start("udevadm", QStringList() << "control" << "--reload-rules"); + reloadProcess.waitForFinished(10000); + + if (reloadProcess.exitCode() != 0) { + qCWarning(appLog) << "Failed to reload udev rules. Error:" << reloadProcess.readAllStandardError(); + return false; + } + + QProcess triggerProcess; + qCInfo(appLog) << "Triggering udev rules"; + triggerProcess.start("udevadm", QStringList() << "trigger"); + triggerProcess.waitForFinished(10000); + + if (triggerProcess.exitCode() != 0) { + qCWarning(appLog) << "Failed to trigger udev rules. Error:" << triggerProcess.readAllStandardError(); + return false; + } + + if (!enable_device) { + EnableSqlManager::getInstance()->insertDataToAuthorizedTable(hclass, name, sPath, value, true, strDriver); + qCInfo(appLog) << "insertDataToAuthorizedTable"; + } else { + EnableSqlManager::getInstance()->removeDataFromAuthorizedTable(value); + qCInfo(appLog) << "removeDataFromAuthorizedTable"; + } + + qCInfo(appLog) << "Keyboard udev rule created and applied successfully"; + emit sigUpdate(); + return true; +} + void ControlInterface::disableInDevice() { if (!getUserAuthorPasswd()) diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.h b/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.h index f2609df2..994a28a2 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.h +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.h @@ -13,6 +13,23 @@ #include #include +// Udev rules directory paths +/* + * Udev rules are read from the following directories in priority order: + * 1. /etc/udev/rules.d/ - Highest priority, for local administrator custom rules + * 2. /run/udev/rules.d/ - Runtime rules (may not exist on all systems) + * 3. /usr/local/lib/udev/rules.d/ - Local software rules (recommended for applications) + * 4. /usr/lib/udev/rules.d/ - System default rules + * + * All rules files are processed in lexical order, regardless of the directory they live in. + * Files with identical filenames replace each other. Files in /etc have the highest priority. + * Rule files must have the extension .rules; other extensions are ignored. + */ +#define UDEV_RULES_PATH_LOCAL "/usr/local/lib/udev/rules.d" +#define UDEV_RULES_PATH_SYSTEM "/etc/udev/rules.d" +#define UDEV_RULES_PATH_RUNTIME "/run/udev/rules.d" +#define UDEV_RULES_PATH_LIB "/usr/lib/udev/rules.d" + class DriverManager; class ModCore; class ControlInterface : public QDBusService, protected QDBusContext @@ -69,6 +86,17 @@ public slots: * @return */ Q_SCRIPTABLE bool enablePrinter(const QString &hclass, const QString &name, const QString &path, bool enable_device); + /** + * @brief enableKeyboard 启用/禁用键盘设备 + * @param hclass 设备类型 + * @param name 设备名称 + * @param sPath 设备路径 + * @param value 设备唯一标识 + * @param enable_device 是否启用 + * @param strDriver 驱动名称 + * @return 操作是否成功 + */ + Q_SCRIPTABLE bool enableKeyboard(const QString& vid, const QString& pid, const QString &hclass, const QString &name, const QString &sPath, const QString &value, bool enable_device, const QString strDriver); /** * @brief disableOutDevice 禁用设备 * @param devInfo 设备信息 diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp index 9d37eb58..93c4417c 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp @@ -204,6 +204,45 @@ bool EnableUtils::ioctlOperateNetworkLogicalName(const QString &logicalName, boo return true; } +bool EnableUtils::validateAndNormalizeVidPid(const QString &vid, const QString &pid, QString &normalizedVid, QString &normalizedPid) +{ + qCDebug(appLog) << "Validating and normalizing VID:" << vid << "PID:" << pid; + + // Check if VID or PID is empty + if (vid.isEmpty() || pid.isEmpty()) { + qCWarning(appLog) << "VID or PID is empty for validation"; + return false; + } + + // Normalize VID + normalizedVid = vid.toLower(); + if (normalizedVid.startsWith("0x")) { + normalizedVid = normalizedVid.mid(2); + } + + // Normalize PID + normalizedPid = pid.toLower(); + if (normalizedPid.startsWith("0x")) { + normalizedPid = normalizedPid.mid(2); + } + + // Validate VID and PID format (should be 4 characters each after normalization) + if (normalizedVid.length() != 4 || normalizedPid.length() != 4) { + qCWarning(appLog) << "Invalid VID or PID format after normalization. VID:" << normalizedVid << "PID:" << normalizedPid; + return false; + } + + // Validate that VID and PID contain only hex characters + QRegularExpression hexPattern("^[0-9a-f]{4}$"); + if (!hexPattern.match(normalizedVid).hasMatch() || !hexPattern.match(normalizedPid).hasMatch()) { + qCWarning(appLog) << "VID or PID contains non-hex characters. VID:" << normalizedVid << "PID:" << normalizedPid; + return false; + } + + qCDebug(appLog) << "VID and PID validation successful. Normalized VID:" << normalizedVid << "Normalized PID:" << normalizedPid; + return true; +} + bool EnableUtils::getMapInfo(const QString &item, QMap &mapInfo) { qCDebug(appLog) << "Parsing device info map"; diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h index ba02af52..36223d9d 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h @@ -18,7 +18,6 @@ class EnableUtils */ static void disableOutDevice(const QString &info); - /** * @brief disableInDevice 禁用非外设 */ @@ -31,7 +30,17 @@ class EnableUtils * @return */ static bool ioctlOperateNetworkLogicalName(const QString &logicalName, bool enable); - + + /** + * @brief validateAndNormalizeVidPid 验证并标准化VID和PID + * @param vid 输入的VID + * @param pid 输入的PID + * @param normalizedVid 输出的标准化VID + * @param normalizedPid 输出的标准化PID + * @return 验证是否成功 + */ + static bool validateAndNormalizeVidPid(const QString &vid, const QString &pid, QString &normalizedVid, QString &normalizedPid); + /** * @brief getMapInfo 解析usb信息 * @param item diff --git a/deepin-devicemanager/src/DeviceManager/DeviceInput.cpp b/deepin-devicemanager/src/DeviceManager/DeviceInput.cpp index 010e3d4c..ee96cd9d 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceInput.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceInput.cpp @@ -102,6 +102,24 @@ TomlFixMethod DeviceInput::setInfoFromTomlOneByOne(const QMap void DeviceInput::setInfoFromHwinfo(const QMap &mapInfo) { qCDebug(appLog) << "setInfoFromHwinfo"; + if (mapInfo.find("path") != mapInfo.end()) { + qCDebug(appLog) << "Path found in mapInfo, setting basic attributes."; + setAttribute(mapInfo, "name", m_Name); + setAttribute(mapInfo, "driver", m_Driver); + setAttribute(mapInfo, "path", m_SysPath); + setAttribute(mapInfo, "unique_id", m_VID_PID); + if (m_SysPath.contains("usb", Qt::CaseInsensitive)) { + m_Interface = "USB"; + } + if (m_VID_PID.size() == 10) { + m_VID = m_VID_PID.mid(2, 4); + m_PID = m_VID_PID.last(4); + } + m_Enable = false; + // m_CanUninstall = !driverIsKernelIn(m_Driver); + qCWarning(appLog) << "Device disabled, skip further processing"; + return; + } //取触摸板的状态 if (mapInfo.find("Model") != mapInfo.end() && mapInfo["Model"].contains("Touchpad", Qt::CaseInsensitive)) { @@ -125,6 +143,8 @@ void DeviceInput::setInfoFromHwinfo(const QMap &mapInfo) setAttribute(mapInfo, "Unique ID", m_UniqueID); setAttribute(mapInfo, "Module Alias", m_Modalias); setAttribute(mapInfo, "VID_PID", m_VID_PID); + setAttribute(mapInfo, "PID", m_PID); + setAttribute(mapInfo, "VID", m_VID); m_PhysID = m_VID_PID; // 防止Serial ID为空 if (m_SerialID.isEmpty()) { @@ -500,6 +520,45 @@ const QString DeviceInput::getOverviewInfo() EnableDeviceStatus DeviceInput::setEnable(bool e) { qCDebug(appLog) << "setEnable"; + + // 处理键盘设备 + if (m_HardwareClass == "keyboard") { + qCDebug(appLog) << "setEnable keyboard device"; + + if (m_Interface.contains("USB", Qt::CaseInsensitive)) { + qCDebug(appLog) << "USB keyboard detected, using backend service"; + + QString vid = getVID(); + QString pid = getPID(); + + if (vid.isEmpty() || pid.isEmpty()) { + qCWarning(appLog) << "Cannot enable keyboard: VID or PID is empty. VID:" << vid << "PID:" << pid; + return EDS_Faild; + } + + // Use DeviceManager's validation function + QString safeVid, safePid; + if (!DeviceManager::instance()->validateKeyboardVidPid(vid, pid, safeVid, safePid)) { + qCWarning(appLog) << "VID or PID validation failed. VID:" << vid << "PID:" << pid; + return EDS_Faild; + } + + bool res = DBusEnableInterface::getInstance()->enableKeyboard(safeVid, safePid, m_HardwareClass, m_Name, m_SysPath, m_VID_PID, e, m_Driver); + if (res) { + m_Enable = e; + qCDebug(appLog) << "Keyboard enable operation successful:" << e; + } else { + qCWarning(appLog) << "Keyboard enable operation failed"; + } + + return res ? EDS_Success : EDS_Faild; + } else { + qCDebug(appLog) << "Non-USB keyboard detected, cannot disable/enable using udev rules"; + return EDS_Faild; + } + } + + // 处理触摸板设备 if (m_Name.contains("Touchpad", Qt::CaseInsensitive)) { qCDebug(appLog) << "setEnable touchpad"; DBusTouchPad::instance()->setEnable(e); @@ -537,12 +596,6 @@ EnableDeviceStatus DeviceInput::setEnable(bool e) bool DeviceInput::enable() { // qCDebug(appLog) << "enable"; - // 键盘不可禁用 - if (m_HardwareClass == "keyboard") { - // qCDebug(appLog) << "enable keyboard"; - m_Enable = true; - } - // qCDebug(appLog) << "enable end"; return m_Enable; } diff --git a/deepin-devicemanager/src/DeviceManager/DeviceInput.h b/deepin-devicemanager/src/DeviceManager/DeviceInput.h index 69bfd819..8d07034a 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceInput.h +++ b/deepin-devicemanager/src/DeviceManager/DeviceInput.h @@ -154,7 +154,6 @@ class DeviceInput : public DeviceBaseInfo * @brief loadTableData:加载表头信息 */ void loadTableData() override; - private: /** diff --git a/deepin-devicemanager/src/DeviceManager/DeviceManager.cpp b/deepin-devicemanager/src/DeviceManager/DeviceManager.cpp index 4eb26b48..4d269930 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceManager.cpp +++ b/deepin-devicemanager/src/DeviceManager/DeviceManager.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // 其它头文件 #include "DeviceCpu.h" @@ -1523,8 +1524,60 @@ void DeviceManager::setCameraInfoFromLshw(const QMap &mapInfo) void DeviceManager::addKeyboardDevice(DeviceInput *const device) { // qCDebug(appLog) << "Adding keyboard device"; - // 添加键盘 - m_ListDeviceKeyboard.append(device); + + QString vid = device->getVID(); + QString pid = device->getPID(); + + if (vid.isEmpty() || pid.isEmpty()) { + qCDebug(appLog) << "VID or PID is empty, adding keyboard device without verification"; + device->deleteLater(); + return; + } + + // Use DeviceManager's validation function + QString normalizedVid, normalizedPid; + if (!validateKeyboardVidPid(vid, pid, normalizedVid, normalizedPid)) { + qCWarning(appLog) << "VID or PID validation failed. VID:" << vid << "PID:" << pid; + device->deleteLater(); + return; + } + + QProcess process; + process.start("lsusb"); + process.waitForFinished(3000); + + if (process.exitCode() != 0) { + qCWarning(appLog) << "Failed to execute lsusb command, adding keyboard device without verification"; + device->deleteLater(); + return; + } + + QString lsusbOutput = process.readAllStandardOutput(); + + // lsusb output: Bus xxx Device xxx: ID xxxx:xxxx Description + QRegularExpression regex(QString("ID\\s+([0-9a-fA-F]{4}):([0-9a-fA-F]{4})")); + QRegularExpressionMatchIterator iterator = regex.globalMatch(lsusbOutput); + + bool deviceExists = false; + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + QString lsusbVid = match.captured(1).toLower(); + QString lsusbPid = match.captured(2).toLower(); + + if (lsusbVid == normalizedVid && lsusbPid == normalizedPid) { + deviceExists = true; + qCDebug(appLog) << "Found matching device in lsusb output:" << lsusbVid << ":" << lsusbPid; + break; + } + } + + if (deviceExists) { + m_ListDeviceKeyboard.append(device); + qCDebug(appLog) << "Keyboard device added successfully"; + } else { + qCDebug(appLog) << "Keyboard device not found in lsusb output, device not added"; + device->deleteLater(); + } } void DeviceManager::setKeyboardInfoFromLshw(const QMap &mapInfo) @@ -2125,3 +2178,42 @@ void DeviceManager::setCpuFrequencyIsCur(const bool &flag) device->setFrequencyIsCur(flag); } } + +bool DeviceManager::validateKeyboardVidPid(const QString &vid, const QString &pid, QString &normalizedVid, QString &normalizedPid) +{ + qCDebug(appLog) << "Validating keyboard VID:" << vid << "PID:" << pid; + + // Check if VID or PID is empty + if (vid.isEmpty() || pid.isEmpty()) { + qCWarning(appLog) << "VID or PID is empty for keyboard validation"; + return false; + } + + // Normalize VID + normalizedVid = vid.toLower(); + if (normalizedVid.startsWith("0x")) { + normalizedVid = normalizedVid.mid(2); + } + + // Normalize PID + normalizedPid = pid.toLower(); + if (normalizedPid.startsWith("0x")) { + normalizedPid = normalizedPid.mid(2); + } + + // Validate VID and PID format (should be 4 characters each after normalization) + if (normalizedVid.length() != 4 || normalizedPid.length() != 4) { + qCWarning(appLog) << "Invalid VID or PID format after normalization. VID:" << normalizedVid << "PID:" << normalizedPid; + return false; + } + + // Validate that VID and PID contain only hex characters + QRegularExpression hexPattern("^[0-9a-f]{4}$"); + if (!hexPattern.match(normalizedVid).hasMatch() || !hexPattern.match(normalizedPid).hasMatch()) { + qCWarning(appLog) << "VID or PID contains non-hex characters. VID:" << normalizedVid << "PID:" << normalizedPid; + return false; + } + + qCDebug(appLog) << "Keyboard VID and PID validation successful. Normalized VID:" << normalizedVid << "Normalized PID:" << normalizedPid; + return true; +} diff --git a/deepin-devicemanager/src/DeviceManager/DeviceManager.h b/deepin-devicemanager/src/DeviceManager/DeviceManager.h index 61ee5438..80624f62 100644 --- a/deepin-devicemanager/src/DeviceManager/DeviceManager.h +++ b/deepin-devicemanager/src/DeviceManager/DeviceManager.h @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include // for std::sort //class DeviceMouse; class DeviceCpu; @@ -629,6 +632,16 @@ class DeviceManager : public QObject */ void setCpuFrequencyIsCur(const bool &flag); + /** + * @brief validateKeyboardVidPid:校验有效的vid和pid + * @param vid + * @param pid + * @param normalizedVid + * @param normalizedPid + * @return + */ + bool validateKeyboardVidPid(const QString &vid, const QString &pid, QString &normalizedVid, QString &normalizedPid); + protected: DeviceManager(); ~DeviceManager(); diff --git a/deepin-devicemanager/src/EnableControl/DBusEnableInterface.cpp b/deepin-devicemanager/src/EnableControl/DBusEnableInterface.cpp index 0b87551d..4916fac9 100644 --- a/deepin-devicemanager/src/EnableControl/DBusEnableInterface.cpp +++ b/deepin-devicemanager/src/EnableControl/DBusEnableInterface.cpp @@ -97,6 +97,19 @@ bool DBusEnableInterface::enablePrinter(const QString &hclass, const QString &na return false; } +bool DBusEnableInterface::enableKeyboard(const QString &vid, const QString &pid, const QString &hclass, const QString &name, const QString &sPath, const QString &value, bool enable_device, const QString &strDriver) +{ + qCDebug(appLog) << "Enable keyboard - vid:" << vid << "pid:" << pid << "hclass:" << hclass << "name:" << name << "sPath:" << sPath << "value:" << value << "enable:" << enable_device << "driver:" << strDriver; + QDBusReply reply = mp_Iface->call("enableKeyboard", vid, pid, hclass, name, sPath, value, enable_device, strDriver); + if (reply.isValid()) { + bool result = reply.value(); + qCInfo(appLog) << "Keyboard enable operation result:" << result; + return result; + } + qCWarning(appLog) << "Invalid DBus reply when enabling keyboard"; + return false; +} + void DBusEnableInterface::init() { qCDebug(appLog) << "Initialize DBus connection"; diff --git a/deepin-devicemanager/src/EnableControl/DBusEnableInterface.h b/deepin-devicemanager/src/EnableControl/DBusEnableInterface.h index e1ffcacb..c43623e0 100644 --- a/deepin-devicemanager/src/EnableControl/DBusEnableInterface.h +++ b/deepin-devicemanager/src/EnableControl/DBusEnableInterface.h @@ -72,6 +72,20 @@ class DBusEnableInterface */ bool enablePrinter(const QString& hclass, const QString& name, const QString& path, bool enable_device); + /** + * @brief enableKeyboard 启用/禁用键盘设备 + * @param vid 设备VID + * @param pid 设备PID + * @param hclass 设备类型 + * @param name 设备名称 + * @param sPath 设备路径 + * @param value 设备唯一标识 + * @param enable_device 是否启用 + * @param strDriver 驱动名称 + * @return 操作是否成功 + */ + bool enableKeyboard(const QString& vid, const QString& pid, const QString& hclass, const QString& name, const QString& sPath, const QString& value, bool enable_device, const QString& strDriver); + protected: DBusEnableInterface(); diff --git a/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp b/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp index 36518168..943be265 100644 --- a/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp +++ b/deepin-devicemanager/src/GenerateDevice/DeviceGenerator.cpp @@ -1097,7 +1097,6 @@ void DeviceGenerator::getKeyboardInfoFromHwinfo() DeviceInput *device = new DeviceInput(); device->setInfoFromHwinfo(*it); device->setHardwareClass("keyboard"); - device->setCanEnable(false); DeviceManager::instance()->addKeyboardDevice(device); addBusIDFromHwinfo((*it)["SysFS BusID"]); }