File indexing completed on 2024-04-14 03:50:32

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(const 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     if (ini.status()) {
0036         qCritical("Error loading file: %s", argv[1]);
0037         return 1;
0038     }
0039 
0040     if (argc == 3) {
0041         // Support an optional 2nd argument pointing to the output file
0042         //
0043         // This is safer to use in build systems than
0044         // "kauth-policy-gen foo.actions > foo.policy" because when using a
0045         // redirection "foo.policy" is created even if kauth-policy-gen fails.
0046         // This means the first call to make fails, but a second call succeeds
0047         // because an empty "foo.policy" exists.
0048         if (!freopen(argv[2], "w", stdout)) {
0049             qCritical("Failed to open %s for writing: %s", argv[2], strerror(errno));
0050             return 1;
0051         }
0052     }
0053 
0054     output(parse(ini), parseDomain(ini));
0055 }
0056 
0057 QList<Action> parse(QSettings &ini)
0058 {
0059     QList<Action> actions;
0060 
0061     // example: [org.kde.kcontrol.kcmfoo.save]
0062     const QRegularExpression actionExp(QRegularExpression::anchoredPattern(QStringLiteral("[0-9a-z]+(\\.[0-9a-z]+)*")));
0063 
0064     // example: Description[ca]=Mòdul de control del Foo.
0065     const QRegularExpression descriptionExp(QRegularExpression::anchoredPattern(QStringLiteral("description(?:\\[(\\w+)\\])?")),
0066                                             QRegularExpression::CaseInsensitiveOption);
0067 
0068     // example: Name[ca]=Mòdul de control del Foo
0069     const QRegularExpression nameExp(QRegularExpression::anchoredPattern(QStringLiteral("name(?:\\[(\\w+)\\])?")), QRegularExpression::CaseInsensitiveOption);
0070 
0071     // example: Policy=auth_admin
0072     const QRegularExpression policyExp(QRegularExpression::anchoredPattern(QStringLiteral("(?:yes|no|auth_self|auth_admin)")));
0073 
0074     const auto listChilds = ini.childGroups();
0075     for (const QString &name : listChilds) {
0076         Action action;
0077 
0078         if (name == QLatin1String("Domain")) {
0079             continue;
0080         }
0081 
0082         if (!actionExp.match(name).hasMatch()) {
0083             qCritical("Wrong action syntax: %s\n", name.toLatin1().data());
0084             exit(1);
0085         }
0086 
0087         action.name = name;
0088         ini.beginGroup(name);
0089 
0090         const auto listChildKeys = ini.childKeys();
0091         for (const QString &key : listChildKeys) {
0092             QRegularExpressionMatch match;
0093             if ((match = descriptionExp.match(key)).hasMatch()) {
0094                 QString lang = match.captured(1);
0095 
0096                 if (lang.isEmpty()) {
0097                     lang = QString::fromLatin1("en");
0098                 }
0099 
0100                 action.descriptions.insert(lang, ini.value(key).toString());
0101 
0102             } else if ((match = nameExp.match(key)).hasMatch()) {
0103                 QString lang = match.captured(1);
0104 
0105                 if (lang.isEmpty()) {
0106                     lang = QString::fromLatin1("en");
0107                 }
0108 
0109                 action.messages.insert(lang, ini.value(key).toString());
0110 
0111             } else if (key.toLower() == QLatin1String("policy")) {
0112                 QString policy = ini.value(key).toString();
0113                 if (!policyExp.match(policy).hasMatch()) {
0114                     qCritical("Wrong policy: %s", policy.toLatin1().data());
0115                     exit(1);
0116                 }
0117                 action.policy = policy;
0118 
0119             } else if (key.toLower() == QLatin1String("policyinactive")) {
0120                 QString policyInactive = ini.value(key).toString();
0121                 if (!policyExp.match(policyInactive).hasMatch()) {
0122                     qCritical("Wrong policy: %s", policyInactive.toLatin1().data());
0123                     exit(1);
0124                 }
0125                 action.policyInactive = policyInactive;
0126 
0127             } else if (key.toLower() == QLatin1String("persistence")) {
0128                 QString persistence = ini.value(key).toString();
0129                 if (persistence != QLatin1String("session") && persistence != QLatin1String("always")) {
0130                     qCritical("Wrong persistence: %s", persistence.toLatin1().data());
0131                     exit(1);
0132                 }
0133                 action.persistence = persistence;
0134             }
0135         }
0136 
0137         if (action.policy.isEmpty() || action.messages.isEmpty() || action.descriptions.isEmpty()) {
0138             qCritical("Missing option in action: %s", name.toLatin1().data());
0139             exit(1);
0140         }
0141         ini.endGroup();
0142 
0143         actions.append(action);
0144     }
0145 
0146     return actions;
0147 }
0148 
0149 QMap<QString, QString> parseDomain(const QSettings &ini)
0150 {
0151     QMap<QString, QString> rethash;
0152 
0153     if (ini.childGroups().contains(QString::fromLatin1("Domain"))) {
0154         if (ini.contains(QString::fromLatin1("Domain/Name"))) {
0155             rethash[QString::fromLatin1("vendor")] = ini.value(QString::fromLatin1("Domain/Name")).toString();
0156         }
0157         if (ini.contains(QString::fromLatin1("Domain/URL"))) {
0158             rethash[QString::fromLatin1("vendorurl")] = ini.value(QString::fromLatin1("Domain/URL")).toString();
0159         }
0160         if (ini.contains(QString::fromLatin1("Domain/Icon"))) {
0161             rethash[QString::fromLatin1("icon")] = ini.value(QString::fromLatin1("Domain/Icon")).toString();
0162         }
0163     }
0164 
0165     return rethash;
0166 }