diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/AuthDialog.cpp | 377 | ||||
-rw-r--r-- | src/AuthDialog.h | 90 | ||||
-rw-r--r-- | src/AuthDialog.ui | 171 | ||||
-rw-r--r-- | src/authdetails.ui | 91 | ||||
-rw-r--r-- | src/main.cpp | 48 | ||||
-rw-r--r-- | src/org.freedesktop.PolicyKit.AuthenticationAgent.xml | 15 | ||||
-rw-r--r-- | src/org.kde.Polkit1AuthAgent.xml | 10 | ||||
-rw-r--r-- | src/policykit1-kde.notifyrc | 177 | ||||
-rw-r--r-- | src/policykitkde.cpp | 46 | ||||
-rw-r--r-- | src/policykitkde.h | 38 | ||||
-rw-r--r-- | src/policykitlistener.cpp | 237 | ||||
-rw-r--r-- | src/policykitlistener.h | 80 | ||||
-rw-r--r-- | src/polkit-kde-authentication-agent-1.desktop.in | 24 |
13 files changed, 1404 insertions, 0 deletions
diff --git a/src/AuthDialog.cpp b/src/AuthDialog.cpp new file mode 100644 index 0000000..f2c4886 --- /dev/null +++ b/src/AuthDialog.cpp @@ -0,0 +1,377 @@ +/* This file is part of the KDE project + Copyright (C) 2007-2008 Gökçen Eraslan <gokcen@pardus.org.tr> + Copyright (C) 2008 Dirk Mueller <mueller@kde.org> + Copyright (C) 2008 Daniel Nicoletti <dantti85-pk@yahoo.com.br> + Copyright (C) 2008-2010 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "AuthDialog.h" + +#include <QtCore/QProcess> +#include <QtGui/QPainter> +#include <QtGui/QStandardItemModel> +#include <KDebug> + +#include <KToolInvocation> +#include <KUser> + +#include <PolkitQt1/Authority> +#include <PolkitQt1/Details> + +#include <KWindowSystem> +#include <KNotification> + +AuthDialog::AuthDialog(const QString &actionId, + const QString &message, + const QString &iconName, + const PolkitQt1::Details &details, + const PolkitQt1::Identity::List &identities, + WId parent) + : KDialog(0) +{ + // KAuth is able to circumvent polkit's limitations, and manages to send the wId to the auth agent. + // If we received it, we use KWindowSystem to associate this dialog correctly. + if (parent > 0) { + kDebug() << "Associating the dialog with " << parent << " this dialog is " << winId(); + + // Set the parent + KWindowSystem::setMainWindow(this, parent); + + // Set modal + KWindowSystem::setState(winId(), NET::Modal); + } + + setupUi(mainWidget()); + setButtons(Ok | Cancel | Details); + + if (message.isEmpty()) { + kWarning() << "Could not get action message for action."; + lblHeader->hide(); + } else { + kDebug() << "Message of action: " << message; + lblHeader->setText("<h3>" + message + "</h3>"); + setCaption(message); + m_message = message; + } + + // loads the standard key icon + QPixmap icon = KIconLoader::global()->loadIcon("dialog-password", + KIconLoader::NoGroup, + KIconLoader::SizeHuge, + KIconLoader::DefaultState); + // create a painter to paint the action icon over the key icon + QPainter painter(&icon); + const int iconSize = icon.size().width(); + // the the emblem icon to size 32 + int overlaySize = 32; + // try to load the action icon + const QPixmap pixmap = KIconLoader::global()->loadIcon(iconName, + KIconLoader::NoGroup, + overlaySize, + KIconLoader::DefaultState, + QStringList(), + 0, + true); + // if we're able to load the action icon paint it over the + // key icon. + if (!pixmap.isNull()) { + QPoint startPoint; + // bottom right corner + startPoint = QPoint(iconSize - overlaySize - 2, + iconSize - overlaySize - 2); + painter.drawPixmap(startPoint, pixmap); + } + + setWindowIcon(icon); + lblPixmap->setPixmap(icon); + + // find action description for actionId + foreach(const PolkitQt1::ActionDescription &desc, PolkitQt1::Authority::instance()->enumerateActionsSync()) { + if (actionId == desc.actionId()) { + m_actionDescription = desc; + kDebug() << "Action description has been found" ; + break; + } + } + + AuthDetails *detailsDialog = new AuthDetails(details, m_actionDescription, m_appname, this); + setDetailsWidget(detailsDialog); + + userCB->hide(); + lePassword->setFocus(); + + errorMessageKTW->hide(); + + // If there is more than 1 identity we will show the combobox for user selection + if (identities.size() > 1) { + connect(userCB, SIGNAL(currentIndexChanged(int)), + this, SLOT(on_userCB_currentIndexChanged(int))); + + createUserCB(identities); + } else { + userCB->addItem("", QVariant(identities[0].toString())); + userCB->setCurrentIndex(0); + } +} + +AuthDialog::~AuthDialog() +{ +} + +void AuthDialog::accept() +{ + // Do nothing, do not close the dialog. This is needed so that the dialog stays + lePassword->setEnabled(false); + return; +} + +void AuthDialog::setRequest(const QString &request, bool requiresAdmin) +{ + kDebug() << request; + PolkitQt1::Identity identity = adminUserSelected(); + if (request.startsWith(QLatin1String("password:"), Qt::CaseInsensitive)) { + if (requiresAdmin) { + if (!identity.isValid()) { + lblPassword->setText(i18n("Password for root:")); + } else { + lblPassword->setText(i18n("Password for %1:", + identity.toString().remove("unix-user:"))); + } + } else { + lblPassword->setText(i18n("Password:")); + } + } else if (request.startsWith(QLatin1String("password or swipe finger:"), + Qt::CaseInsensitive)) { + if (requiresAdmin) { + if (!identity.isValid()) { + lblPassword->setText(i18n("Password or swipe finger for root:")); + } else { + lblPassword->setText(i18n("Password or swipe finger for %1:", + identity.toString().remove("unix-user:"))); + } + } else { + lblPassword->setText(i18n("Password or swipe finger:")); + } + } else { + lblPassword->setText(request); + } + +} + +void AuthDialog::setOptions() +{ + lblContent->setText(i18n("An application is attempting to perform an action that requires privileges." + " Authentication is required to perform this action.")); +} + +void AuthDialog::createUserCB(const PolkitQt1::Identity::List &identities) +{ + /* if we've already built the list of admin users once, then avoid + * doing it again.. (this is mainly used when the user entered the + * wrong password and the dialog is recycled) + */ + if (identities.count() && (userCB->count() - 1) != identities.count()) { + // Clears the combobox in the case some user be added + userCB->clear(); + + // Adds a Dummy user + userCB->addItem(i18n("Select User"), qVariantFromValue<QString> (QString())); + qobject_cast<QStandardItemModel *>(userCB->model())->item(userCB->count()-1)->setEnabled(false); + + // For each user + int index = 1; // Start at 1 because of the "Select User" entry + int currentUserIndex = -1; + const KUser currentUser; + foreach(const PolkitQt1::Identity &identity, identities) { + // First check to see if the user is valid + kDebug() << "User: " << identity.toString(); + const KUser user(identity.toString().remove("unix-user:")); + if (!user.isValid()) { + kWarning() << "User invalid: " << user.loginName(); + continue; + } + + // Display user Full Name IF available + QString display; + if (!user.property(KUser::FullName).toString().isEmpty()) { + display = i18nc("%1 is the full user name, %2 is the user login name", "%1 (%2)", user.property(KUser::FullName).toString(), user.loginName()); + } else { + display = user.loginName(); + } + + KIcon icon; + // load user icon face + if (!user.faceIconPath().isEmpty()) { + icon = KIcon(user.faceIconPath()); + } else { + icon = KIcon("user-identity"); + } + // appends the user item + userCB->addItem(icon, display, qVariantFromValue<QString> (identity.toString())); + + if (user == currentUser) { + currentUserIndex = index; + } + ++index; + } + + // Show the widget and set focus + if (currentUserIndex != -1) { + userCB->setCurrentIndex(currentUserIndex); + } + userCB->show(); + } +} + +PolkitQt1::Identity AuthDialog::adminUserSelected() const +{ + if (userCB->currentIndex() == -1) + return PolkitQt1::Identity(); + + QString id = userCB->itemData(userCB->currentIndex()).toString(); + if (id.isEmpty()) + return PolkitQt1::Identity(); + return PolkitQt1::Identity::fromString(id); +} + +void AuthDialog::on_userCB_currentIndexChanged(int /*index*/) +{ + PolkitQt1::Identity identity = adminUserSelected(); + // itemData is Null when "Select user" is selected + if (!identity.isValid()) { + lePassword->setEnabled(false); + lblPassword->setEnabled(false); + enableButtonOk(false); + } else { + lePassword->setEnabled(true); + lblPassword->setEnabled(true); + enableButtonOk(true); + // We need this to restart the auth with the new user + emit adminUserSelected(identity); + // git password label focus + lePassword->setFocus(); + } +} + +QString AuthDialog::password() const +{ + return lePassword->text(); +} + +void AuthDialog::authenticationFailure() +{ + errorMessageKTW->setText(i18n("Authentication failure, please try again."), KTitleWidget::ErrorMessage); + QFont bold = font(); + bold.setBold(true); + lblPassword->setFont(bold); + lePassword->setEnabled(true); + lePassword->clear(); + lePassword->setFocus(); +} + +void AuthDialog::showEvent(QShowEvent *event) +{ + KDialog::showEvent(event); + if (winId() != KWindowSystem::activeWindow()) + { + KNotification *notification = new KNotification("authenticate", this, + KNotification::Persistent | KNotification::CloseWhenWidgetActivated); + kDebug() << "Notificate: " << notification->eventId(); + notification->setText(m_message); + QPixmap icon = KIconLoader::global()->loadIcon("dialog-password", + KIconLoader::NoGroup, + KIconLoader::SizeHuge, + KIconLoader::DefaultState); + notification->setPixmap(icon); + notification->setActions(QStringList() << i18n("Switch to dialog") << i18n("Cancel")); + + connect(notification, SIGNAL(activated(uint)), this, SLOT(notificationActivated(uint))); + notification->sendEvent(); + } + +} + +void AuthDialog::notificationActivated(unsigned int action) +{ + kDebug() << "notificationActivated: " << action; + if (action == 1) + { + KWindowSystem::forceActiveWindow(winId()); + } +} + +AuthDetails::AuthDetails(const PolkitQt1::Details &details, + const PolkitQt1::ActionDescription &actionDescription, + const QString &appname, + QWidget *parent) + : QWidget(parent) +{ + setupUi(this); + + app_label->setText(appname); + + foreach(const QString &key, details.keys()) { //krazy:exclude=foreach (Details is not a map/hash, but rather a method) + int row = gridLayout->rowCount() + 1; + + QLabel *keyLabel = new QLabel(this); + keyLabel->setText(i18nc("%1 is the name of a detail about the current action " + "provided by polkit", "%1:", key)); + gridLayout->addWidget(keyLabel, row, 0); + + QLabel *valueLabel = new QLabel(this); + valueLabel->setText(details.lookup(key)); + gridLayout->addWidget(valueLabel, row, 1); + } + + action_label->setText(actionDescription.description()); + + action_label->setTipText(i18n("Click to edit %1", actionDescription.actionId())); + action_label->setUrl(actionDescription.actionId()); + + QString vendor = actionDescription.vendorName(); + QString vendorUrl = actionDescription.vendorUrl(); + + if (!vendor.isEmpty()) { + vendorUL->setText(vendor); + vendorUL->setTipText(i18n("Click to open %1", vendorUrl)); + vendorUL->setUrl(vendorUrl); + } else if (!vendorUrl.isEmpty()) { + vendorUL->setText(vendorUrl); + vendorUL->setTipText(i18n("Click to open %1", vendorUrl)); + vendorUL->setUrl(vendorUrl); + } else { + vendorL->hide(); + vendorUL->hide(); + } + + connect(vendorUL, SIGNAL(leftClickedUrl(QString)), SLOT(openUrl(QString))); + connect(action_label, SIGNAL(leftClickedUrl(QString)), SLOT(openAction(QString))); +} + +void AuthDetails::openUrl(const QString& url) +{ + KToolInvocation::invokeBrowser(url); +} + +void AuthDetails::openAction(const QString &url) +{ + QProcess::startDetached("polkit-kde-authorization", QStringList() << url); +} + +#include "AuthDialog.moc" diff --git a/src/AuthDialog.h b/src/AuthDialog.h new file mode 100644 index 0000000..620145d --- /dev/null +++ b/src/AuthDialog.h @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2007-2008 Gökçen Eraslan <gokcen@pardus.org.tr> + Copyright (C) 2008 Daniel Nicoletti <dantti85-pk@yahoo.com.br> + Copyright (C) 2010 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef AUTHDIALOG_H +#define AUTHDIALOG_H + +#include "ui_AuthDialog.h" +#include "ui_authdetails.h" + +#include <PolkitQt1/Identity> +#include <PolkitQt1/ActionDescription> + +namespace PolkitQt1 +{ +class Details; +} + +class AuthDialog : public KDialog, private Ui::AuthDialog +{ + Q_OBJECT +public: + AuthDialog(const QString &actionId, + const QString &message, + const QString &iconName, + const PolkitQt1::Details &details, + const PolkitQt1::Identity::List &identities, + WId parent); + ~AuthDialog(); + + void setRequest(const QString &request, bool requiresAdmin); + void setOptions(); + QString password() const; + void authenticationFailure(); + + PolkitQt1::Identity adminUserSelected() const; + + PolkitQt1::ActionDescription m_actionDescription; + +signals: + void adminUserSelected(PolkitQt1::Identity); + +public slots: + virtual void accept(); + +private slots: + void on_userCB_currentIndexChanged(int index); + void notificationActivated(unsigned int action); + +private: + QString m_appname; + QString m_message; + + void createUserCB(const PolkitQt1::Identity::List &identities); + void showEvent(QShowEvent *); +}; + +class AuthDetails : public QWidget, private Ui::AuthDetails +{ + Q_OBJECT +public: + AuthDetails(const PolkitQt1::Details &details, + const PolkitQt1::ActionDescription &actionDescription, + const QString &appname, + QWidget *parent); + +private slots: + void openUrl(const QString&); + void openAction(const QString&); +}; + +#endif // AUTHDIALOG_H diff --git a/src/AuthDialog.ui b/src/AuthDialog.ui new file mode 100644 index 0000000..3b9bbc6 --- /dev/null +++ b/src/AuthDialog.ui @@ -0,0 +1,171 @@ +<ui version="4.0" > + <class>AuthDialog</class> + <widget class="QWidget" name="AuthDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>335</width> + <height>193</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout" > + <item rowspan="6" row="0" column="0" > + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QLabel" name="lblPixmap" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string notr="true">Lock Icon here</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + <property name="buddy" > + <cstring>lePassword</cstring> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>92</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="0" column="1" colspan="3" > + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QLabel" name="lblHeader" > + <property name="sizePolicy" > + <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string notr="true"><b>Header is here!</b></string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + <property name="buddy" > + <cstring>lePassword</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblContent" > + <property name="sizePolicy" > + <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string notr="true"><i>Content</i></string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="1" colspan="3" > + <widget class="KTitleWidget" name="errorMessageKTW" /> + </item> + <item row="3" column="1" colspan="2" > + <widget class="QLabel" name="lblPassword" > + <property name="text" > + <string>Password:</string> + </property> + <property name="buddy" > + <cstring>lePassword</cstring> + </property> + </widget> + </item> + <item row="3" column="3" > + <widget class="KLineEdit" name="lePassword" > + <property name="echoMode" > + <enum>QLineEdit::Password</enum> + </property> + <property name="passwordMode" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1" colspan="3" > + <widget class="KComboBox" name="userCB" /> + </item> + </layout> + <zorder>errorMessageKTW</zorder> + <zorder>lblPassword</zorder> + <zorder>lePassword</zorder> + <zorder>cbRemember</zorder> + <zorder>cbSessionOnly</zorder> + <zorder>horizontalSpacer</zorder> + <zorder>userCB</zorder> + </widget> + <customwidgets> + <customwidget> + <class>KComboBox</class> + <extends>QComboBox</extends> + <header>kcombobox.h</header> + </customwidget> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + <customwidget> + <class>KTitleWidget</class> + <extends>QWidget</extends> + <header>ktitlewidget.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>userCB</tabstop> + <tabstop>lePassword</tabstop> + <tabstop>cbRemember</tabstop> + <tabstop>cbSessionOnly</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>cbRemember</sender> + <signal>toggled(bool)</signal> + <receiver>cbSessionOnly</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel" > + <x>259</x> + <y>161</y> + </hint> + <hint type="destinationlabel" > + <x>161</x> + <y>169</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/authdetails.ui b/src/authdetails.ui new file mode 100644 index 0000000..6dda5da --- /dev/null +++ b/src/authdetails.ui @@ -0,0 +1,91 @@ +<ui version="4.0" > + <class>AuthDetails</class> + <widget class="QWidget" name="AuthDetails" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>273</width> + <height>80</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout" > + <item row="1" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Application:</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Action:</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="vendorL" > + <property name="text" > + <string>Vendor:</string> + </property> + </widget> + </item> + <item row="3" column="1" colspan="3" > + <widget class="KUrlLabel" name="vendorUL" > + <property name="text" > + <string>Vendor:</string> + </property> + <property name="tipText" > + <string/> + </property> + <property name="useTips" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1" colspan="3" > + <widget class="KUrlLabel" name="action_label" > + <property name="text" > + <string>Action:</string> + </property> + <property name="tipText" > + <string/> + </property> + <property name="useTips" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="0" colspan="4" > + <widget class="Line" name="line" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="1" column="1" colspan="3" > + <widget class="QLabel" name="app_label" > + <property name="text" > + <string>Application:</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KUrlLabel</class> + <extends>QLabel</extends> + <header>kurllabel.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..33ef236 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Jaroslav Reznik <jreznik@redhat.com> + + 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include <KCmdLineArgs> +#include <KAboutData> +#include <KLocale> +#include <KCrash> + +#include "policykitkde.h" + +int main(int argc, char *argv[]) +{ + KAboutData aboutData("Polkit1AuthAgent", "polkit-kde-authentication-agent-1", ki18n("PolicyKit1-KDE"), "0.99.0", + ki18n("PolicyKit1-KDE"), KAboutData::License_GPL, + ki18n("(c) 2009 Red Hat, Inc.")); + aboutData.addAuthor(ki18n("Jaroslav Reznik"), ki18n("Maintainer"), "jreznik@redhat.com"); + aboutData.setProductName("policykit-kde/polkit-kde-authentication-agent-1"); + + KCmdLineArgs::init(argc, argv, &aboutData); + + if (!PolicyKitKDE::start()) { + qWarning("PolicyKitKDE is already running!\n"); + return 0; + } + + KCrash::setFlags(KCrash::AutoRestart); + + PolicyKitKDE agent; + agent.disableSessionManagement(); + agent.exec(); +} diff --git a/src/org.freedesktop.PolicyKit.AuthenticationAgent.xml b/src/org.freedesktop.PolicyKit.AuthenticationAgent.xml new file mode 100644 index 0000000..f5aa8ef --- /dev/null +++ b/src/org.freedesktop.PolicyKit.AuthenticationAgent.xml @@ -0,0 +1,15 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.PolicyKit.AuthenticationAgent"> + <method name="ObtainAuthorization" > + <!-- IN: PolicyKit action identifier; see PolKitAction --> + <arg direction="in" type="s" name="action_id" /> + <!-- IN: X11 window ID for the top-level X11 window the dialog will be transient for. --> + <arg direction="in" type="u" name="xid" /> + <!-- IN: Process ID to grant authorization to --> + <arg direction="in" type="u" name="pid" /> + <!-- OUT: whether the user gained the authorization --> + <arg direction="out" type="b" name="gained_authorization" /> + </method> + </interface> +</node> diff --git a/src/org.kde.Polkit1AuthAgent.xml b/src/org.kde.Polkit1AuthAgent.xml new file mode 100644 index 0000000..0aa39de --- /dev/null +++ b/src/org.kde.Polkit1AuthAgent.xml @@ -0,0 +1,10 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.kde.Polkit1AuthAgent"> + <method name="setWIdForAction"> + <arg type="s" direction="in" /> + <arg type="t" direction="in" /> + </method> + </interface> +</node> diff --git a/src/policykit1-kde.notifyrc b/src/policykit1-kde.notifyrc new file mode 100644 index 0000000..bc91c3f --- /dev/null +++ b/src/policykit1-kde.notifyrc @@ -0,0 +1,177 @@ +[Global] +IconName=dialog-password +Comment=PolicyKit authentication dialog +Comment[ar]=مربع حوار الاستيثاق PolicyKit +Comment[bs]=PolicyKit dijalog provjere identiteta +Comment[ca]=Diàleg d'autenticació del PolicyKit +Comment[ca@valencia]=Diàleg d'autenticació del PolicyKit +Comment[cs]=Ověřovací dialog PolicyKitu +Comment[da]=PolicyKit autentificeringsdialog +Comment[de]=PolicyKit-Berechtigungsdialog +Comment[el]=PolicyKit διάλογος πιστοποίησης +Comment[en_GB]=PolicyKit authentication dialogue +Comment[es]=Diálogo de autenticación de PolicyKit +Comment[et]=PolicyKiti autentimisdialoog +Comment[fi]=PolicyKit-tunnistautumisikkuna +Comment[fr]=Boîte de dialogue d'authentification de PolicyKit +Comment[gl]=Diálogo de autenticación de PolicyKit +Comment[hr]=PolicyKit-ov dijaloški prozor za autentifikaciju +Comment[hu]=PolicyKit hitelesítési párbeszédablak +Comment[it]=Finestra di autenticazione di PolicyKit +Comment[km]=ប្រអប់ផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ PolicyKit +Comment[lt]=PolicyKit tapatumo nustatymo dialogas +Comment[ms]=Dialog pengesahan PolicyKit +Comment[nb]=PolicyKit autentiseringsdialog +Comment[nds]=Regelsett-Identiteetprööv-Dialoog +Comment[nl]=Authenticatiedialoog van PolicyKit +Comment[pa]=ਪਾਲਸੀਕਿੱਟ ਪਰਮਾਣਕਿਤਾ ਡਾਈਲਾਗ +Comment[pl]=Okno dialogowe uwierzytelnienia PolicyKit +Comment[pt]=Janela de autenticação do PolicyKit +Comment[pt_BR]=Diálogo de autenticação do PolicyKit +Comment[ro]=Dialog de autentificare PolicyKit +Comment[ru]=Диалоговое окно аутентификации PolicyKit +Comment[sl]=Pogovorno okno overitve PolicyKit +Comment[sr]=Полисикитов дијалог за аутентификовање +Comment[sr@ijekavian]=Полисикитов дијалог за аутентификовање +Comment[sr@ijekavianlatin]=PolicyKitov dijalog za autentifikovanje +Comment[sr@latin]=PolicyKitov dijalog za autentifikovanje +Comment[sv]=Policykit behörighetsdialogruta +Comment[tr]=PolicyKit kimlik doğrulama penceresi +Comment[ug]=PolicyKit سالاھىيەت دەلىللەش سۆزلەشكۈسى +Comment[uk]=Діалогове вікно розпізнавання PolicyKit +Comment[vi]=Hộp thoại xác thực PolicyKit +Comment[x-test]=xxPolicyKit authentication dialogxx +Comment[zh_CN]=PolicyKit 认证对话框 +Comment[zh_TW]=PolicyKit 認證對話框 +Name=policykit1-kde +Name[ar]=policykit1-kde +Name[bs]=policykit1-kde +Name[ca]=policykit1-kde +Name[ca@valencia]=policykit1-kde +Name[cs]=policykit1-kde +Name[da]=policykit1-kde +Name[de]=policykit1-kde +Name[el]=policykit1-kde +Name[en_GB]=policykit1-kde +Name[es]=policykit1-kde +Name[et]=policykit1-kde +Name[fi]=policykit1-kde +Name[fr]=policykit1-kde +Name[gl]=policykit1-kde +Name[hr]=policykit1-kde +Name[hu]=policykit1-kde +Name[it]=policykit1-kde +Name[km]=policykit1-kde +Name[lt]=policykit1-kde +Name[ms]=policykit1-kde +Name[nb]=policykit1-kde +Name[nds]=Regelsett1-KDE +Name[nl]=policykit1-kde +Name[pa]=policykit1-kde +Name[pl]=policykit1-kde +Name[pt]=policykit1-kde +Name[pt_BR]=policykit1-kde +Name[ro]=policykit1-kde +Name[ru]=policykit1-kde +Name[sk]=policykit1-kde +Name[sl]=policykit1-kde +Name[sr]=Полисикит1‑КДЕ +Name[sr@ijekavian]=Полисикит1‑КДЕ +Name[sr@ijekavianlatin]=PolicyKit1‑KDE +Name[sr@latin]=PolicyKit1‑KDE +Name[sv]=policykit1-kde +Name[tr]=policykit1-kde +Name[ug]=policykit1-kde +Name[uk]=policykit1-kde +Name[vi]=policykit1-kde +Name[x-test]=xxpolicykit1-kdexx +Name[zh_CN]=policykit1-kde +Name[zh_TW]=policykit1-kde + +[Event/authenticate] +Name=authenticate +Name[ar]=الاستيثاق +Name[bs]=autentifikacija +Name[ca]=autentica +Name[ca@valencia]=autentica +Name[cs]=ověřit +Name[da]=autentificér +Name[de]=Berechtigen +Name[el]=πιστοποίηση +Name[en_GB]=authenticate +Name[es]=autenticarse +Name[et]=Autentimine +Name[fi]=tunnistaudu +Name[fr]=s'authentifier +Name[gl]=autenticar +Name[hr]=autentifikacija +Name[hu]=hitelesítés +Name[it]=autenticazione +Name[km]=ផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ +Name[lt]=nustatyti tapatybę +Name[ms]=pengesahan +Name[nb]=autentiser +Name[nds]=Identiteet pröven +Name[nl]=authenticatie +Name[pa]=ਪਰਮਾਣਕਿਤਾ +Name[pl]=uwierzytelnij +Name[pt]=autenticar +Name[pt_BR]=autenticar +Name[ro]=autentificare +Name[ru]=аутентификация +Name[sl]=overi +Name[sr]=Аутентификовање +Name[sr@ijekavian]=Аутентификовање +Name[sr@ijekavianlatin]=Autentifikovanje +Name[sr@latin]=Autentifikovanje +Name[sv]=behörighetskontrollera +Name[tr]=yetkilendir +Name[ug]=سالاھىيەت دەلىللەش +Name[uk]=розпізнавання +Name[vi]=xác thực +Name[x-test]=xxauthenticatexx +Name[zh_CN]=认证 +Name[zh_TW]=認證 +Comment=You are required to authenticate +Comment[ar]=أنت مطالب بالاستيثاق +Comment[bs]=Trebate se autentificirati +Comment[ca]=Se us demana que us autentiqueu +Comment[ca@valencia]=Se vos demana que vos autentiqueu +Comment[cs]=Je vyžadováno ověření totožnosti +Comment[da]=Du skal autentificere +Comment[de]=Sie benötigen eine Berechtigung +Comment[el]=Απαιτείται να πιστοποιηθείτε +Comment[en_GB]=You are required to authenticate +Comment[es]=Es necesario que se autentique +Comment[et]=Vajalik on autentimine +Comment[fi]=Tunnistautuminen vaaditaan +Comment[fr]=Vous devez vous authentifier +Comment[gl]=Debe identificarse. +Comment[hr]=Potrebno je autentificirati se +Comment[hu]=Hitelesítés szükséges +Comment[it]=Devi effettuare l'autenticazione +Comment[km]=អ្នកត្រូវបានស្នើ ដើម្បីផ្ទៀងផ្ទាត់ភាពត្រឹមត្រូវ +Comment[lt]=Reikia nustatyti jūsų tapatybę +Comment[nb]=Du må autentisere +Comment[nds]=Identiteetprööv deit noot +Comment[nl]=Authenticeren is verplicht +Comment[pa]=ਤੁਹਾਨੂੰ ਪਰਮਾਣਿਤ ਹੋਣ ਦੀ ਲੋੜ ਹੈ +Comment[pl]=Musisz się uwierzytelnić +Comment[pt]=É necessária a sua autenticação +Comment[pt_BR]=É necessária a sua autenticação +Comment[ro]=Vi se solicită autentificarea +Comment[ru]=Необходимо выполнить аутентификацию +Comment[sl]=Zahtevana je overitev +Comment[sr]=Треба да се аутентификујете +Comment[sr@ijekavian]=Треба да се аутентификујете +Comment[sr@ijekavianlatin]=Treba da se autentifikujete +Comment[sr@latin]=Treba da se autentifikujete +Comment[sv]=Det krävs att din behörighet kontrolleras +Comment[tr]=Kimlik doğrulaması yapmanız gerekiyor +Comment[ug]=سالاھىيىتىڭىزنى دەلىللەش زۆرۈر +Comment[uk]=Вам слід пройти розпізнавання +Comment[vi]=Bạn được yêu cầu phải xác thực +Comment[x-test]=xxYou are required to authenticatexx +Comment[zh_CN]=您需要认证 +Comment[zh_TW]=您需要認證 +Action=Popup diff --git a/src/policykitkde.cpp b/src/policykitkde.cpp new file mode 100644 index 0000000..55f979b --- /dev/null +++ b/src/policykitkde.cpp @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Jaroslav Reznik <jreznik@redhat.com> + + 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "policykitkde.h" + +#include <KDebug> +#include <PolkitQt1/Subject> + +PolicyKitKDE::PolicyKitKDE() + : m_listener(new PolicyKitListener(this)) +{ + setQuitOnLastWindowClosed(false); + + PolkitQt1::UnixSessionSubject session(getpid()); + + bool result = m_listener->registerListener(session, "/org/kde/PolicyKit1/AuthenticationAgent"); + + kDebug() << result; + + if (!result) { + kDebug() << "Couldn't register listener!"; + exit(1); + } +} + +PolicyKitKDE::~PolicyKitKDE() +{ + m_listener->deleteLater(); +} diff --git a/src/policykitkde.h b/src/policykitkde.h new file mode 100644 index 0000000..85ce6b2 --- /dev/null +++ b/src/policykitkde.h @@ -0,0 +1,38 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Jaroslav Reznik <jreznik@redhat.com> + + 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef POLICYKITKDE_H +#define POLICYKITKDE_H + +#include <KUniqueApplication> + +#include "policykitlistener.h" + +class PolicyKitKDE : public KUniqueApplication +{ + Q_OBJECT +public: + PolicyKitKDE(); + virtual ~PolicyKitKDE(); +private: + PolicyKitListener *m_listener; +}; + +#endif diff --git a/src/policykitlistener.cpp b/src/policykitlistener.cpp new file mode 100644 index 0000000..6da9461 --- /dev/null +++ b/src/policykitlistener.cpp @@ -0,0 +1,237 @@ +/* This file is part of the KDE project + Copyright (C) 2009 Jaroslav Reznik <jreznik@redhat.com> + + 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "policykitlistener.h" +#include "AuthDialog.h" + +#include <KDebug> +#include <KWindowSystem> + +#include <PolkitQt1/Agent/Listener> +#include <PolkitQt1/Agent/Session> +#include <PolkitQt1/Subject> +#include <PolkitQt1/Identity> +#include <PolkitQt1/Details> +#include <QtDBus/QDBusConnection> + +#include "polkit1authagentadaptor.h" + +PolicyKitListener::PolicyKitListener(QObject *parent) + : Listener(parent) + , m_inProgress(false) + , m_selectedUser(0) +{ + (void) new Polkit1AuthAgentAdaptor(this); + + if (!QDBusConnection::sessionBus().registerObject("/org/kde/Polkit1AuthAgent", this, + QDBusConnection::ExportScriptableSlots | + QDBusConnection::ExportScriptableProperties | + QDBusConnection::ExportAdaptors)) { + kWarning() << "Could not initiate DBus helper!"; + } + + kDebug() << "Listener online"; +} + +PolicyKitListener::~PolicyKitListener() +{ +} + +void PolicyKitListener::setWIdForAction(const QString& action, qulonglong wID) +{ + kDebug() << "On to the handshake"; + m_actionsToWID[action] = wID; +} + +void PolicyKitListener::initiateAuthentication(const QString &actionId, + const QString &message, + const QString &iconName, + const PolkitQt1::Details &details, + const QString &cookie, + const PolkitQt1::Identity::List &identities, + PolkitQt1::Agent::AsyncResult* result) +{ + kDebug() << "Initiating authentication"; + + if (m_inProgress) { + result->setError(i18n("Another client is already authenticating, please try again later.")); + result->setCompleted(); + kDebug() << "Another client is already authenticating, please try again later."; + return; + } + + m_identities = identities; + m_cookie = cookie; + m_result = result; + m_session.clear(); + + m_inProgress = true; + + WId parentId = 0; + + if (m_actionsToWID.contains(actionId)) { + parentId = m_actionsToWID[actionId]; + } + + m_dialog = new AuthDialog(actionId, message, iconName, details, identities, parentId); + connect(m_dialog.data(), SIGNAL(okClicked()), SLOT(dialogAccepted())); + connect(m_dialog.data(), SIGNAL(cancelClicked()), SLOT(dialogCanceled())); + connect(m_dialog.data(), SIGNAL(adminUserSelected(PolkitQt1::Identity)), SLOT(userSelected(PolkitQt1::Identity))); + + kDebug() << "WinId of the dialog is " << m_dialog.data()->winId() << m_dialog.data()->effectiveWinId(); + m_dialog.data()->setOptions(); + m_dialog.data()->show(); + KWindowSystem::forceActiveWindow(m_dialog.data()->winId()); + kDebug() << "WinId of the shown dialog is " << m_dialog.data()->winId() << m_dialog.data()->effectiveWinId(); + + if (identities.length() == 1) { + m_selectedUser = identities[0]; + } else { + m_selectedUser = m_dialog.data()->adminUserSelected(); + } + + m_numTries = 0; + tryAgain(); +} + +void PolicyKitListener::tryAgain() +{ + kDebug() << "Trying again"; +// test!!! + m_wasCancelled = false; + + // We will create new session only when some user is selected + if (m_selectedUser.isValid()) { + m_session = new Session(m_selectedUser, m_cookie, m_result); + connect(m_session.data(), SIGNAL(request(QString,bool)), this, SLOT(request(QString,bool))); + connect(m_session.data(), SIGNAL(completed(bool)), this, SLOT(completed(bool))); + connect(m_session.data(), SIGNAL(showError(QString)), this, SLOT(showError(QString))); + + m_session.data()->initiate(); + } + +} + +void PolicyKitListener::finishObtainPrivilege() +{ + kDebug() << "Finishing obtaining privileges"; + + // Number of tries increase only when some user is selected + if (m_selectedUser.isValid()) { + m_numTries++; + } + + if (!m_gainedAuthorization && !m_wasCancelled && !m_dialog.isNull()) { + m_dialog.data()->authenticationFailure(); + + if (m_numTries < 3) { + m_session.data()->deleteLater(); + + tryAgain(); + return; + } + } + + if (!m_session.isNull()) { + m_session.data()->result()->setCompleted(); + } else { + m_result->setCompleted(); + } + m_session.data()->deleteLater(); + + if (!m_dialog.isNull()) { + m_dialog.data()->hide(); + m_dialog.data()->deleteLater(); + } + + m_inProgress = false; + + kDebug() << "Finish obtain authorization:" << m_gainedAuthorization; +} + +bool PolicyKitListener::initiateAuthenticationFinish() +{ + kDebug() << "Finishing authentication"; + return true; +} + +void PolicyKitListener::cancelAuthentication() +{ + kDebug() << "Cancelling authentication"; + + m_wasCancelled = true; + finishObtainPrivilege(); +} + +void PolicyKitListener::request(const QString &request, bool echo) +{ + Q_UNUSED(echo); + kDebug() << "Request: " << request; + + if (!m_dialog.isNull()) { + m_dialog.data()->setRequest(request, m_selectedUser.isValid() && + m_selectedUser.toString() == "unix-user:root"); + } +} + +void PolicyKitListener::completed(bool gainedAuthorization) +{ + kDebug() << "Completed: " << gainedAuthorization; + + m_gainedAuthorization = gainedAuthorization; + + finishObtainPrivilege(); +} + +void PolicyKitListener::showError(const QString &text) +{ + kDebug() << "Error: " << text; +} + +void PolicyKitListener::dialogAccepted() +{ + kDebug() << "Dialog accepted"; + + if (!m_dialog.isNull()) { + m_session.data()->setResponse(m_dialog.data()->password()); + } +} + +void PolicyKitListener::dialogCanceled() +{ + kDebug() << "Dialog cancelled"; + + m_wasCancelled = true; + if (!m_session.isNull()) { + m_session.data()->cancel(); + } + + finishObtainPrivilege(); +} + +void PolicyKitListener::userSelected(const PolkitQt1::Identity &identity) +{ + m_selectedUser = identity; + // If some user is selected we must destroy existing session + if (!m_session.isNull()) { + m_session.data()->deleteLater(); + } + tryAgain(); +} diff --git a/src/policykitlistener.h b/src/policykitlistener.h new file mode 100644 index 0000000..21286fc --- /dev/null +++ b/src/policykitlistener.h @@ -0,0 +1,80 @@ +#ifndef POLICYKITLISTENER_H +#define POLICYKITLISTENER_H + +/* This file is part of the KDE project + Copyright (C) 2009 Jaroslav Reznik <jreznik@redhat.com> + + 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include <PolkitQt1/Agent/Listener> + +#include <QtCore/QWeakPointer> +#include <QtCore/QHash> + +class AuthDialog; + +using namespace PolkitQt1::Agent; + +class PolicyKitListener : public Listener +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.Polkit1AuthAgent") +public: + PolicyKitListener(QObject *parent = 0); + virtual ~PolicyKitListener(); + +public slots: + void initiateAuthentication(const QString &actionId, + const QString &message, + const QString &iconName, + const PolkitQt1::Details &details, + const QString &cookie, + const PolkitQt1::Identity::List &identities, + PolkitQt1::Agent::AsyncResult* result); + bool initiateAuthenticationFinish(); + void cancelAuthentication(); + + void tryAgain(); + void finishObtainPrivilege(); + + void request(const QString &request, bool echo); + void completed(bool gainedAuthorization); + void showError(const QString &text); + + void setWIdForAction(const QString &action, qulonglong wID); + /* void showInfo(const QString &text); */ +private: + QWeakPointer<AuthDialog> m_dialog; + QWeakPointer<Session> m_session; + bool m_inProgress; + bool m_gainedAuthorization; + bool m_wasCancelled; + int m_numTries; + PolkitQt1::Identity::List m_identities; + PolkitQt1::Agent::AsyncResult* m_result; + QString m_cookie; + PolkitQt1::Identity m_selectedUser; + QHash< QString, qulonglong > m_actionsToWID; + +private slots: + void dialogAccepted(); + void dialogCanceled(); + void userSelected(const PolkitQt1::Identity &identity); +}; + +#endif diff --git a/src/polkit-kde-authentication-agent-1.desktop.in b/src/polkit-kde-authentication-agent-1.desktop.in new file mode 100644 index 0000000..aa088cc --- /dev/null +++ b/src/polkit-kde-authentication-agent-1.desktop.in @@ -0,0 +1,24 @@ + +[Desktop Entry] +Name=PolicyKit Authentication Agent +Name[da]=PolicyKit autentificeringsagent +Name[en_GB]=PolicyKit Authentication Agent +Name[et]=PolicyKiti autentimisagent +Name[pt]=Agente de Autenticação do PolicyKit +Name[sv]=Policykit behörighetskontrollverktyg +Name[uk]=Агент розпізнавання PolicyKit +Name[x-test]=xxPolicyKit Authentication Agentxx +Comment=PolicyKit Authentication Agent +Comment[da]=PolicyKit autentificeringsagent +Comment[en_GB]=PolicyKit Authentication Agent +Comment[et]=PolicyKiti autentimisagent +Comment[pt]=Agente de Autenticação do PolicyKit +Comment[sv]=Policykit behörighetskontrollverktyg +Comment[uk]=Агент розпізнавання PolicyKit +Comment[x-test]=xxPolicyKit Authentication Agentxx +Exec=${LIBEXEC_INSTALL_DIR}/polkit-kde-authentication-agent-1 +Terminal=false +Type=Application +Categories= +X-Desktop-File-Install-Version=0.15 +OnlyShowIn=KDE; |