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 QList<Action> actions;
60
61 // example: [org.kde.kcontrol.kcmfoo.save]
62 const QRegularExpression actionExp(QRegularExpression::anchoredPattern(QStringLiteral("[0-9a-z]+(\\.[0-9a-z]+)*")));
63
64 // example: Description[ca]=Mòdul de control del Foo.
65 const QRegularExpression descriptionExp(QRegularExpression::anchoredPattern(QStringLiteral("description(?:\\[(\\w+)\\])?")),
66 QRegularExpression::CaseInsensitiveOption);
67
68 // example: Name[ca]=Mòdul de control del Foo
69 const QRegularExpression nameExp(QRegularExpression::anchoredPattern(QStringLiteral("name(?:\\[(\\w+)\\])?")), QRegularExpression::CaseInsensitiveOption);
70
71 // example: Policy=auth_admin
72 const QRegularExpression policyExp(QRegularExpression::anchoredPattern(QStringLiteral("(?:yes|no|auth_self|auth_admin)")));
73
74 const auto listChilds = ini.childGroups();
75 for (const QString &name : listChilds) {
76 Action action;
77
78 if (name == QLatin1String("Domain")) {
79 continue;
80 }
81
82 if (!actionExp.match(subject: name).hasMatch()) {
83 qCritical(msg: "Wrong action syntax: %s\n", name.toLatin1().data());
84 exit(status: 1);
85 }
86
87 action.name = name;
88 ini.beginGroup(prefix: name);
89
90 const auto listChildKeys = ini.childKeys();
91 for (const QString &key : listChildKeys) {
92 QRegularExpressionMatch match;
93 if ((match = descriptionExp.match(subject: key)).hasMatch()) {
94 QString lang = match.captured(nth: 1);
95
96 if (lang.isEmpty()) {
97 lang = QString::fromLatin1(ba: "en");
98 }
99
100 action.descriptions.insert(key: lang, value: ini.value(key).toString());
101
102 } else if ((match = nameExp.match(subject: key)).hasMatch()) {
103 QString lang = match.captured(nth: 1);
104
105 if (lang.isEmpty()) {
106 lang = QString::fromLatin1(ba: "en");
107 }
108
109 action.messages.insert(key: lang, value: ini.value(key).toString());
110
111 } else if (key.toLower() == QLatin1String("policy")) {
112 QString policy = ini.value(key).toString();
113 if (!policyExp.match(subject: policy).hasMatch()) {
114 qCritical(msg: "Wrong policy: %s", policy.toLatin1().data());
115 exit(status: 1);
116 }
117 action.policy = policy;
118
119 } else if (key.toLower() == QLatin1String("policyinactive")) {
120 QString policyInactive = ini.value(key).toString();
121 if (!policyExp.match(subject: policyInactive).hasMatch()) {
122 qCritical(msg: "Wrong policy: %s", policyInactive.toLatin1().data());
123 exit(status: 1);
124 }
125 action.policyInactive = policyInactive;
126
127 } else if (key.toLower() == QLatin1String("persistence")) {
128 QString persistence = ini.value(key).toString();
129 if (persistence != QLatin1String("session") && persistence != QLatin1String("always")) {
130 qCritical(msg: "Wrong persistence: %s", persistence.toLatin1().data());
131 exit(status: 1);
132 }
133 action.persistence = persistence;
134 }
135 }
136
137 if (action.policy.isEmpty() || action.messages.isEmpty() || action.descriptions.isEmpty()) {
138 qCritical(msg: "Missing option in action: %s", name.toLatin1().data());
139 exit(status: 1);
140 }
141 ini.endGroup();
142
143 actions.append(t: action);
144 }
145
146 return actions;
147}
148
149QMap<QString, QString> parseDomain(const QSettings &ini)
150{
151 QMap<QString, QString> rethash;
152
153 if (ini.childGroups().contains(str: QString::fromLatin1(ba: "Domain"))) {
154 if (ini.contains(key: QString::fromLatin1(ba: "Domain/Name"))) {
155 rethash[QString::fromLatin1(ba: "vendor")] = ini.value(key: QString::fromLatin1(ba: "Domain/Name")).toString();
156 }
157 if (ini.contains(key: QString::fromLatin1(ba: "Domain/URL"))) {
158 rethash[QString::fromLatin1(ba: "vendorurl")] = ini.value(key: QString::fromLatin1(ba: "Domain/URL")).toString();
159 }
160 if (ini.contains(key: QString::fromLatin1(ba: "Domain/Icon"))) {
161 rethash[QString::fromLatin1(ba: "icon")] = ini.value(key: QString::fromLatin1(ba: "Domain/Icon")).toString();
162 }
163 }
164
165 return rethash;
166}
167

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