File indexing completed on 2025-02-09 06:35:13

0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0002 // SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org>
0003 
0004 #include "helper.h"
0005 
0006 #include <array>
0007 #include <QDebug>
0008 #include <QProcess>
0009 #include <QStandardPaths>
0010 
0011 #include <KAuth/HelperSupport>
0012 
0013 template<typename Output, typename... Input>
0014 auto make_array(Input&&... args) -> std::array<Output, sizeof...(args)> // NB: we need suffix notation here so args is defined
0015 {
0016     return {std::forward<Input>(args)...};
0017 }
0018 
0019 KAuth::ActionReply DMIDecodeHelper::systeminformation(const QVariantMap &args)
0020 {
0021     Q_UNUSED(args);
0022 
0023     // PATH is super minimal when invoked through dbus
0024     setenv("PATH", "/usr/sbin:/sbin:/usr/local/sbin", 1);
0025     const QString dmidecode = QStandardPaths::findExecutable("dmidecode");
0026     if (dmidecode.isEmpty()) {
0027         return KAuth::ActionReply::HelperErrorReply();
0028     }
0029 
0030     // NB: Microsoft also outlines a limited set of DMI values to be required for IOT OEM licensing, as such we
0031     //   can rely on the same fields to have sound content . Since this only applies to OEMs we still need to filter
0032     //   out dummy values though and because of that we can grab more fields, since we'll filter them anyway.
0033     // https://docs.microsoft.com/en-us/windows-hardware/manufacture/iot/license-requirements?view=windows-11#smbios-support
0034 
0035     KAuth::ActionReply reply;
0036     for (const auto &key : {QStringLiteral("system-manufacturer"),
0037                             QStringLiteral("system-product-name"),
0038                             QStringLiteral("system-version"),
0039                             QStringLiteral("system-serial-number")}) {
0040         QProcess proc;
0041         proc.start(dmidecode, {QStringLiteral("--string"), key});
0042         proc.waitForFinished();
0043         const QByteArray output = proc.readAllStandardOutput().trimmed();
0044 
0045         if (output.isEmpty() || proc.error() != QProcess::UnknownError || proc.exitStatus() != QProcess::NormalExit) {
0046             continue;
0047         }
0048 
0049         // Fairly exhaustive filter list based on a dozen or so samples gathered from reddit and other places.
0050         // These are values that may appear in the DMI system information but aren't really useful.
0051         static const auto dummyData = make_array<QString>(QStringLiteral("system version"),
0052                                                           QStringLiteral("system product name"),
0053                                                           QStringLiteral("system serial number"),
0054                                                           QStringLiteral("system manufacturer"),
0055                                                           QStringLiteral("to be filled by o.e.m."),
0056                                                           QStringLiteral("standard"), /* sometimes the version is useless */
0057                                                           QStringLiteral("sku"),
0058                                                           QStringLiteral("default string"),
0059                                                           QStringLiteral("not specified"),
0060                                                           QStringLiteral("not applicable")
0061                                                           /* may also be empty, but that is filtered above already */);
0062         if (std::find(dummyData.cbegin(), dummyData.cend(), output.toLower()) != dummyData.cend()) {
0063             continue;
0064         }
0065 
0066         reply.addData(key, output);
0067     }
0068     return reply;
0069 }
0070 
0071 KAUTH_HELPER_MAIN("org.kde.kinfocenter.dmidecode", DMIDecodeHelper)
0072 
0073 #include "moc_helper.cpp"