1/*
2 SPDX-FileCopyrightText: 2008 Nicola Gigante <nicola.gigante@gmail.com>
3 SPDX-FileCopyrightText: 2009 Dario Freddi <drf@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#include "policy-gen.h"
9
10#include <QCoreApplication>
11#include <QDebug>
12#include <QFile>
13#include <QRegularExpression>
14#include <QSettings>
15#include <QStringList>
16
17#include <cerrno>
18#include <cstdio>
19
20using namespace std;
21
22QList<Action> parse(QSettings &ini);
23QMap<QString, QString> parseDomain(const QSettings &ini);
24
25int main(int argc, char **argv)
26{
27 QCoreApplication app(argc, argv);
28
29 if (argc < 2) {
30 qCritical(msg: "Too few arguments");
31 return 1;
32 }
33
34 QSettings ini(QFile::decodeName(localFileName: argv[1]), QSettings::IniFormat);
35 if (ini.status()) {
36 qCritical(msg: "Error loading file: %s", argv[1]);
37 return 1;
38 }
39
40 if (argc == 3) {
41 // Support an optional 2nd argument pointing to the output file
42 //
43 // This is safer to use in build systems than
44 // "kauth-policy-gen foo.actions > foo.policy" because when using a
45 // redirection "foo.policy" is created even if kauth-policy-gen fails.
46 // This means the first call to make fails, but a second call succeeds
47 // because an empty "foo.policy" exists.
48 if (!freopen(filename: argv[2], modes: "w", stdout)) {
49 qCritical(msg: "Failed to open %s for writing: %s", argv[2], strerror(errno));
50 return 1;
51 }
52 }
53
54 output(actions: parse(ini), domain: parseDomain(ini));
55}
56
57QList<Action> parse(QSettings &ini)
58{
59 // clazy:excludeall=use-static-qregularexpression
60 // example: [org.kde.kcontrol.kcmfoo.save]
61 const QRegularExpression actionExp(QRegularExpression::anchoredPattern(QStringLiteral("[0-9a-z]+(\\.[0-9a-z]+)*")));
62 // example: Description[ca]=Mòdul de control del Foo.
63 const QRegularExpression descriptionExp(QRegularExpression::anchoredPattern(QStringLiteral("description(?:\\[(\\w+)\\])?")),
64 QRegularExpression::CaseInsensitiveOption);
65 // example: Name[ca]=Mòdul de control del Foo
66 const QRegularExpression nameExp(QRegularExpression::anchoredPattern(QStringLiteral("name(?:\\[(\\w+)\\])?")), QRegularExpression::CaseInsensitiveOption);
67 // example: Policy=auth_admin
68 const QRegularExpression policyExp(QRegularExpression::anchoredPattern(QStringLiteral("(?:yes|no|auth_self|auth_admin)")));
69
70 QList<Action> actions;
71 const auto listChilds = ini.childGroups();
72 for (const QString &name : listChilds) {
73 Action action;
74
75 if (name == QLatin1String("Domain")) {
76 continue;
77 }
78
79 if (!actionExp.match(subject: name).hasMatch()) {
80 qCritical(msg: "Wrong action syntax: %s\n", name.toLatin1().data());
81 exit(status: 1);
82 }
83
84 action.name = name;
85 ini.beginGroup(prefix: name);
86
87 const QStringList listChildKeys = ini.childKeys();
88 for (const QString &key : listChildKeys) {
89 QRegularExpressionMatch match;
90 if ((match = descriptionExp.match(subject: key)).hasMatch()) {
91 QString lang = match.captured(nth: 1);
92
93 if (lang.isEmpty()) {
94 lang = QString::fromLatin1(ba: "en");
95 }
96
97 action.descriptions.insert(key: lang, value: ini.value(key).toString());
98
99 } else if ((match = nameExp.match(subject: key)).hasMatch()) {
100 QString lang = match.captured(nth: 1);
101
102 if (lang.isEmpty()) {
103 lang = QString::fromLatin1(ba: "en");
104 }
105
106 action.messages.insert(key: lang, value: ini.value(key).toString());
107
108 } else if (key.toLower() == QLatin1String("policy")) {
109 QString policy = ini.value(key).toString();
110 if (!policyExp.match(subject: policy).hasMatch()) {
111 qCritical(msg: "Wrong policy: %s", policy.toLatin1().data());
112 exit(status: 1);
113 }
114 action.policy = policy;
115
116 } else if (key.toLower() == QLatin1String("policyinactive")) {
117 QString policyInactive = ini.value(key).toString();
118 if (!policyExp.match(subject: policyInactive).hasMatch()) {
119 qCritical(msg: "Wrong policy: %s", policyInactive.toLatin1().data());
120 exit(status: 1);
121 }
122 action.policyInactive = policyInactive;
123
124 } else if (key.toLower() == QLatin1String("persistence")) {
125 QString persistence = ini.value(key).toString();
126 if (persistence != QLatin1String("session") && persistence != QLatin1String("always")) {
127 qCritical(msg: "Wrong persistence: %s", persistence.toLatin1().data());
128 exit(status: 1);
129 }
130 action.persistence = persistence;
131 }
132 }
133
134 if (action.policy.isEmpty() || action.messages.isEmpty() || action.descriptions.isEmpty()) {
135 qCritical(msg: "Missing option in action: %s", name.toLatin1().data());
136 exit(status: 1);
137 }
138 ini.endGroup();
139
140 actions.append(t: action);
141 }
142
143 return actions;
144}
145
146QMap<QString, QString> parseDomain(const QSettings &ini)
147{
148 QMap<QString, QString> rethash;
149
150 if (ini.childGroups().contains(str: QString::fromLatin1(ba: "Domain"))) {
151 if (ini.contains(key: QString::fromLatin1(ba: "Domain/Name"))) {
152 rethash[QString::fromLatin1(ba: "vendor")] = ini.value(key: QString::fromLatin1(ba: "Domain/Name")).toString();
153 }
154 if (ini.contains(key: QString::fromLatin1(ba: "Domain/URL"))) {
155 rethash[QString::fromLatin1(ba: "vendorurl")] = ini.value(key: QString::fromLatin1(ba: "Domain/URL")).toString();
156 }
157 if (ini.contains(key: QString::fromLatin1(ba: "Domain/Icon"))) {
158 rethash[QString::fromLatin1(ba: "icon")] = ini.value(key: QString::fromLatin1(ba: "Domain/Icon")).toString();
159 }
160 }
161
162 return rethash;
163}
164

source code of kauth/src/policy-gen/policy-gen.cpp