kde-playground/polkit-kde-kcmodules-1/helper/polkitkde1helper.cpp
Ivailo Monev 9afa3f9dea polkit-kde-kcmmodules-1: adjust to Katie changes
Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
2020-02-01 14:58:22 +00:00

411 lines
16 KiB
C++

/* This file is part of the KDE project
Copyright (C) 2008 Dario Freddi <drf@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#include "polkitkde1helper.h"
#include "helperadaptor.h"
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QTimer>
#include <QtCore/QSettings>
#include <QtCore/QCoreApplication>
#include <QtXml/QDomDocument>
#include <QtDBus/QDBusConnection>
#include <PolkitQt1/Authority>
#include <KLocalizedString>
bool orderByPriorityLessThan(const PKLAEntry &e1, const PKLAEntry &e2)
{
return e1.fileOrder < e2.fileOrder;
}
PolkitKde1Helper::PolkitKde1Helper(QObject* parent)
: QObject(parent)
{
qDBusRegisterMetaType<PKLAEntry>();
qDBusRegisterMetaType<QList<PKLAEntry> >();
(void) new HelperAdaptor(this);
// Register the DBus service
if (!QDBusConnection::systemBus().registerService("org.kde.polkitkde1.helper")) {
qDebug() << QDBusConnection::systemBus().lastError().message();;
QTimer::singleShot(0, QCoreApplication::instance(), SLOT(quit()));
return;
}
if (!QDBusConnection::systemBus().registerObject("/Helper", this)) {
qDebug() << "unable to register service interface to dbus";
QTimer::singleShot(0, QCoreApplication::instance(), SLOT(quit()));
return;
}
}
PolkitKde1Helper::~PolkitKde1Helper()
{
}
void PolkitKde1Helper::saveGlobalConfiguration(const QString& adminIdentities, int systemPriority, int policiesPriority)
{
qDebug() << "Request to save the global configuration by " << message().service();
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.kde.polkitkde1.changesystemconfiguration",
subject, PolkitQt1::Authority::AllowUserInteraction);
switch (result)
{
case PolkitQt1::Authority::Yes:
qDebug() << "Authorized successfully";
break;
case PolkitQt1::Authority::No:
sendErrorReply(QDBusError::AccessDenied, i18n("Changing global configurations is unauthorized"));
return;
default:
sendErrorReply(QDBusError::AccessDenied, i18n("Unknown reply from QPolkit-1\nError: %1", PolkitQt1::Authority::instance()->errorDetails()));
return;
}
// Ok, let's see what we have to save here.
QSettings kdesettings("/etc/polkit-1/polkit-kde-1.conf", QSettings::IniFormat);
kdesettings.setValue("General/ConfigPriority", systemPriority);
kdesettings.setValue("General/PoliciesPriority", policiesPriority);
QString contents = QString("[Configuration]\nAdminIdentities=%1\n").arg(adminIdentities);
qDebug() << contents << "will be wrote to the local authority file";
QFile wfile(QString("/etc/polkit-1/localauthority.conf.d/%1-polkitkde.conf").arg(systemPriority));
if (!wfile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
sendErrorReply(QDBusError::Failed, i18n("Error opening the global configuration file: %1\nError code: %2.", wfile.fileName(), wfile.error()));
return;
}
if (wfile.write(contents.toUtf8()) < 0) {
sendErrorReply(QDBusError::Failed, i18n("Error occurred while writing settings to file: %1.", wfile.fileName()));
return;
}
if (!wfile.flush()) {
sendErrorReply(QDBusError::Failed, i18n("Error occurred while flushing settings to file: %1.", wfile.fileName()));
return;
}
wfile.close();
// TODO: Move files around if the priority was changed
}
QVariantList PolkitKde1Helper::retrievePolicies()
{
qDebug() << "Request to retrieve the action authorizations by " << message().service();
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.kde.polkitkde1.readauthorizations",
subject, PolkitQt1::Authority::AllowUserInteraction);
switch (result)
{
case PolkitQt1::Authority::Yes:
qDebug() << "Authorized successfully";
break;
case PolkitQt1::Authority::No:
sendErrorReply(QDBusError::AccessDenied, i18n("Reading policy settings is unauthorized"));
return QVariantList();
default:
sendErrorReply(QDBusError::AccessDenied, i18n("Unknown reply from QPolkit-1\nError: %1",PolkitQt1::Authority::instance()->errorDetails()));
return QVariantList();
}
return reloadFileList();
}
QVariantList PolkitKde1Helper::entriesFromFile(int filePriority, const QString& filePath)
{
QList< QVariant > retlist;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Failed to open " << filePath;
sendErrorReply(QDBusError::Failed, i18n("Error opening the file: %1\nError code: %2.", file.fileName(), file.error()));
return QVariantList();
}
int priority = 0;
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith('[')) {
// Ok, that's a key entry
PKLAEntry entry;
entry.filePath = filePath;
entry.title = line.split('[').last().split(']').first();
entry.filePriority = filePriority;
entry.fileOrder = priority;
// Now parse over all the rest
while (!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith(QLatin1String("Identity="))) {
entry.identity = line.split("Identity=").last();
} else if (line.startsWith(QLatin1String("Action="))) {
entry.action = line.split("Action=").last();
} else if (line.startsWith(QLatin1String("ResultAny="))) {
entry.resultAny = line.split("ResultAny=").last();
} else if (line.startsWith(QLatin1String("ResultInactive="))) {
entry.resultInactive = line.split("ResultInactive=").last();
} else if (line.startsWith(QLatin1String("ResultActive="))) {
entry.resultActive = line.split("ResultActive=").last();
} else if (line.startsWith('[')) {
// Ouch!!
qWarning() << "The file appears malformed!! " << filePath;
return QVariantList();
}
// Did we parse it all?
if (!entry.identity.isEmpty() && !entry.action.isEmpty() && !entry.resultActive.isEmpty() &&
!entry.resultAny.isEmpty() && !entry.resultInactive.isEmpty() && !entry.filePath.isEmpty()) {
// Awesome, add and wave goodbye. And also increase the priority
++priority;
qDebug() << "PKLA Parsed:" << entry.title << entry.action << entry.identity << entry.resultAny
<< entry.resultInactive << entry.resultActive << entry.fileOrder;
retlist.append(QVariant::fromValue(entry));
break;
}
}
}
}
return retlist;
}
void PolkitKde1Helper::writeImplicitPolicy(const QList<PKLAEntry>& policy)
{
QList<PKLAEntry> entries = policy;
if (entries.empty()) {
return;
}
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.kde.polkitkde1.changeimplicitauthorizations",
subject, PolkitQt1::Authority::AllowUserInteraction);
switch (result)
{
case PolkitQt1::Authority::Yes:
qDebug() << "Authorized successfully";
break;
case PolkitQt1::Authority::No:
sendErrorReply(QDBusError::AccessDenied, i18n("Saving implicit policy settings is unauthorized"));
return;
default:
sendErrorReply(QDBusError::AccessDenied, i18n("Unknown reply from QPolkit-1\nError: %1", PolkitQt1::Authority::instance()->errorDetails()));
return;
}
foreach(const PKLAEntry &entry, entries) {
QDomDocument doc = QDomDocument("policy");
QStringList actionNameSplitted = entry.action.split('.');
QString newName;
QFile *pfile = new QFile("/usr/share/polkit-1/actions/org.freedesktop.kit.policy");
// Search for a valid file
foreach(const QString &nameSplitted , actionNameSplitted) {
newName.append(nameSplitted);
pfile = new QFile("/usr/share/polkit-1/actions/" + newName + ".policy");
if (!pfile->open(QIODevice::ReadOnly)) {
newName.append(".");
delete pfile;
pfile = NULL;
continue;
}
if (!pfile->exists()) {
newName.append(".");
pfile->close();
delete pfile;
pfile = NULL;
continue;
}
// We should now have found a valid file.
break;
}
// Check if the file is valid
if (pfile == NULL) {
sendErrorReply(QDBusError::Failed, i18n("Did not find a valid policy file for the implicit action: %1.", entry.action));
return;
}
// Create XML doc.
QString domDocumentError;
if (!doc.setContent(pfile, &domDocumentError)) {
pfile->close();
sendErrorReply(QDBusError::Failed, i18n("Error occurred while parsing file: %1\nError message: %2", pfile->fileName(), domDocumentError));
return;
}
pfile->close();
QDomElement el = doc.firstChildElement("policyconfig").firstChildElement("action");
while (!el.isNull() && el.attribute("id", QString()) != entry.action) {
el = el.nextSiblingElement("action");
}
el = el.firstChildElement("defaults");
// Delete all its childrens, :P
QDomNodeList nodelist = el.childNodes();
while (nodelist.length() > 0) {
el.removeChild(nodelist.item(0));
}
// Add new elements
QDomElement inactiveElem = el.appendChild(doc.createElement("allow_inactive")).toElement();
QDomElement activeElem = el.appendChild(doc.createElement("allow_active")).toElement();
QDomElement anyElem = el.appendChild(doc.createElement("allow_any")).toElement();
inactiveElem.appendChild(doc.createTextNode(entry.resultInactive));
activeElem.appendChild(doc.createTextNode(entry.resultActive));
anyElem.appendChild(doc.createTextNode(entry.resultAny));
// Write the settings to the XML
if (!pfile->open(QIODevice::WriteOnly)) {
// Failed to write to the file?
qDebug() << "Failed writing to file: " << pfile->fileName();
sendErrorReply(QDBusError::Failed, i18n("Error opening the file: %1\nError code: %2.", pfile->fileName(), pfile->error()));
return;
}
QTextStream stream(pfile);
doc.save(stream, 2);
pfile->close();
delete pfile;
}
}
void PolkitKde1Helper::writePolicy(const QList<PKLAEntry>& policy)
{
QList<PKLAEntry> entries = policy;
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.kde.polkitkde1.changeexplicitauthorizations",
subject, PolkitQt1::Authority::AllowUserInteraction);
switch (result)
{
case PolkitQt1::Authority::Yes:
qDebug() << "Authorized successfully";
break;
case PolkitQt1::Authority::No:
sendErrorReply(QDBusError::AccessDenied, "Saving explicit policy settings is unauthorized");
return;
default:
sendErrorReply(QDBusError::AccessDenied, i18n("Unknown reply from QPolkit-1\nError: %1", PolkitQt1::Authority::instance()->errorDetails()));
return;
}
// First delete all the old files, we do not need them anymore
foreach(const QFileInfo &nestedInfo, oldNestedList) {
QFile::remove(nestedInfo.absoluteFilePath());
}
qSort(entries.begin(), entries.end(), orderByPriorityLessThan);
QSettings kdesettings("/etc/polkit-1/polkit-kde-1.conf", QSettings::IniFormat);
QString pathName = QString("/var/lib/polkit-1/localauthority/%1-polkitkde.d/")
.arg(kdesettings.value("General/PoliciesPriority",75).toInt());
foreach(const PKLAEntry &entry, entries) {
QString fullPath;
// First check if it already has a filePath,
// else generate fullPath from the policy action name
if (!entry.filePath.isEmpty()) {
fullPath = entry.filePath;
} else {
QStringList dotSplittedFileName = entry.action.split('.');
// Skip the action name
dotSplittedFileName.removeLast();
dotSplittedFileName << "pkla";
// Check if the polkitkde.d dir exists. If not, create it.
QDir path(pathName);
if (!path.exists()) {
if (!path.mkpath(path.absolutePath())) {
sendErrorReply(QDBusError::Failed, i18n("Error creating the directory: %1.", path.absolutePath()));
return;
}
}
fullPath = pathName + dotSplittedFileName.join(".");
}
QString contents;
contents.append(formatPKLAEntry(entry));
contents.append('\n');
QFile wfile(fullPath);
if (!wfile.open(QIODevice::Append | QIODevice::Truncate | QIODevice::Text)) {
sendErrorReply(QDBusError::Failed, i18n("Error opening the explicit setting file: %1\nError code: %2.", wfile.fileName(), wfile.error()));
return;
}
if (wfile.write(contents.toUtf8()) < 0) {
sendErrorReply(QDBusError::Failed, i18n("Error occurred while writing explicit settings to file: %1.", wfile.fileName()));
return;
}
if (!wfile.flush()) {
sendErrorReply(QDBusError::Failed, i18n("Error occurred while flushing explicit settings to file: %1.", wfile.fileName()));
return;
}
}
// Reload fileList;
reloadFileList();
}
QString PolkitKde1Helper::formatPKLAEntry(const PKLAEntry& entry)
{
QString retstring;
retstring.append(QString("[%1]\n").arg(entry.title));
retstring.append(QString("Identity=%1\n").arg(entry.identity));
retstring.append(QString("Action=%1\n").arg(entry.action));
retstring.append(QString("ResultAny=%1\n").arg(entry.resultAny));
retstring.append(QString("ResultInactive=%1\n").arg(entry.resultInactive));
retstring.append(QString("ResultActive=%1\n").arg(entry.resultActive));
return retstring;
}
QVariantList PolkitKde1Helper::reloadFileList()
{
QVariantList retlist;
oldNestedList.clear();
// Iterate over the directory and find out everything
QDir baseDir("/var/lib/polkit-1/localauthority/");
QFileInfoList baseList = baseDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QFileInfo &info, baseList) {
int filePriority = info.baseName().split('-').first().toInt();
qDebug() << "Iterating over the directory " << info.absoluteFilePath() << ", which has a priority of " << filePriority;
QDir nestedDir(info.absoluteFilePath());
QFileInfoList nestedList = nestedDir.entryInfoList(QDir::Files);
foreach (const QFileInfo &nestedInfo, nestedList) {
qDebug() << "Parsing file " << nestedInfo.absoluteFilePath();
retlist.append(entriesFromFile(filePriority, nestedInfo.absoluteFilePath()));
}
// Save all the fileinfo's, for a later delete if we choose to save
oldNestedList << nestedList;
}
return retlist;
}