File indexing completed on 2024-04-28 15:18:45

0001 /*
0002     SPDX-FileCopyrightText: 2008 Nicola Gigante <nicola.gigante@gmail.com>
0003     SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include "policy-gen.h"
0009 
0010 #include <QCoreApplication>
0011 #include <QDebug>
0012 #include <QFile>
0013 #include <QRegularExpression>
0014 #include <QSettings>
0015 #include <QStringList>
0016 
0017 #include <cerrno>
0018 #include <cstdio>
0019 
0020 using namespace std;
0021 
0022 QList<Action> parse(QSettings &ini);
0023 QMap<QString, QString> parseDomain(QSettings &ini);
0024 
0025 int main(int argc, char **argv)
0026 {
0027     QCoreApplication app(argc, argv);
0028 
0029     if (argc < 2) {
0030         qCritical("Too few arguments");
0031         return 1;
0032     }
0033 
0034     QSettings ini(QFile::decodeName(argv[1]), QSettings::IniFormat);
0035     // It's UTF-8 by default in Qt6
0036 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0037     ini.setIniCodec("UTF-8");
0038 #endif
0039     if (ini.status()) {
0040         qCritical("Error loading file: %s", argv[1]);
0041         return 1;
0042     }
0043 
0044     if (argc == 3) {
0045         // Support an optional 2nd argument pointing to the output file
0046         //
0047         // This is safer to use in build systems than
0048         // "kauth-policy-gen foo.actions > foo.policy" because when using a
0049         // redirection "foo.policy" is created even if kauth-policy-gen fails.
0050         // This means the first call to make fails, but a second call succeeds
0051         // because an empty "foo.policy" exists.
0052         if (!freopen(argv[2], "w", stdout)) {
0053             qCritical("Failed to open %s for writing: %s", argv[2], strerror(errno));
0054             return 1;
0055         }
0056     }
0057 
0058     output(parse(ini), parseDomain(ini));
0059 }
0060 
0061 QList<Action> parse(QSettings &ini)
0062 {
0063     QList<Action> actions;
0064 
0065     // example: [org.kde.kcontrol.kcmfoo.save]
0066     const QRegularExpression actionExp(QRegularExpression::anchoredPattern(QStringLiteral("[0-9a-z]+(\\.[0-9a-z]+)*")));
0067 
0068     // example: Description[ca]=Mòdul de control del Foo.
0069     const QRegularExpression descriptionExp(QRegularExpression::anchoredPattern(QStringLiteral("description(?:\\[(\\w+)\\])?")),
0070                                             QRegularExpression::CaseInsensitiveOption);
0071 
0072     // example: Name[ca]=Mòdul de control del Foo
0073     const QRegularExpression nameExp(QRegularExpression::anchoredPattern(QStringLiteral("name(?:\\[(\\w+)\\])?")), QRegularExpression::CaseInsensitiveOption);
0074 
0075     // example: Policy=auth_admin
0076     const QRegularExpression policyExp(QRegularExpression::anchoredPattern(QStringLiteral("(?:yes|no|auth_self|auth_admin)")));
0077 
0078     const auto listChilds = ini.childGroups();
0079     for (const QString &name : listChilds) {
0080         Action action;
0081 
0082         if (name == QLatin1String("Domain")) {
0083             continue;
0084         }
0085 
0086         if (!actionExp.match(name).hasMatch()) {
0087             qCritical("Wrong action syntax: %s\n", name.toLatin1().data());
0088             exit(1);
0089         }
0090 
0091         action.name = name;
0092         ini.beginGroup(name);
0093 
0094         const auto listChildKeys = ini.childKeys();
0095         for (const QString &key : listChildKeys) {
0096             QRegularExpressionMatch match;
0097             if ((match = descriptionExp.match(key)).hasMatch()) {
0098                 QString lang = match.captured(1);
0099 
0100                 if (lang.isEmpty()) {
0101                     lang = QString::fromLatin1("en");
0102                 }
0103 
0104                 action.descriptions.insert(lang, ini.value(key).toString());
0105 
0106             } else if ((match = nameExp.match(key)).hasMatch()) {
0107                 QString lang = match.captured(1);
0108 
0109                 if (lang.isEmpty()) {
0110                     lang = QString::fromLatin1("en");
0111                 }
0112 
0113                 action.messages.insert(lang, ini.value(key).toString());
0114 
0115             } else if (key.toLower() == QLatin1String("policy")) {
0116                 QString policy = ini.value(key).toString();
0117                 if (!policyExp.match(policy).hasMatch()) {
0118                     qCritical("Wrong policy: %s", policy.toLatin1().data());
0119                     exit(1);
0120                 }
0121                 action.policy = policy;
0122 
0123             } else if (key.toLower() == QLatin1String("policyinactive")) {
0124                 QString policyInactive = ini.value(key).toString();
0125                 if (!policyExp.match(policyInactive).hasMatch()) {
0126                     qCritical("Wrong policy: %s", policyInactive.toLatin1().data());
0127                     exit(1);
0128                 }
0129                 action.policyInactive = policyInactive;
0130 
0131             } else if (key.toLower() == QLatin1String("persistence")) {
0132                 QString persistence = ini.value(key).toString();
0133                 if (persistence != QLatin1String("session") && persistence != QLatin1String("always")) {
0134                     qCritical("Wrong persistence: %s", persistence.toLatin1().data());
0135                     exit(1);
0136                 }
0137                 action.persistence = persistence;
0138             }
0139         }
0140 
0141         if (action.policy.isEmpty() || action.messages.isEmpty() || action.descriptions.isEmpty()) {
0142             qCritical("Missing option in action: %s", name.toLatin1().data());
0143             exit(1);
0144         }
0145         ini.endGroup();
0146 
0147         actions.append(action);
0148     }
0149 
0150     return actions;
0151 }
0152 
0153 QMap<QString, QString> parseDomain(QSettings &ini)
0154 {
0155     QMap<QString, QString> rethash;
0156 
0157     if (ini.childGroups().contains(QString::fromLatin1("Domain"))) {
0158         if (ini.contains(QString::fromLatin1("Domain/Name"))) {
0159             rethash[QString::fromLatin1("vendor")] = ini.value(QString::fromLatin1("Domain/Name")).toString();
0160         }
0161         if (ini.contains(QString::fromLatin1("Domain/URL"))) {
0162             rethash[QString::fromLatin1("vendorurl")] = ini.value(QString::fromLatin1("Domain/URL")).toString();
0163         }
0164         if (ini.contains(QString::fromLatin1("Domain/Icon"))) {
0165             rethash[QString::fromLatin1("icon")] = ini.value(QString::fromLatin1("Domain/Icon")).toString();
0166         }
0167     }
0168 
0169     return rethash;
0170 }