File indexing completed on 2024-04-21 04:43:23

0001 // This is an example not a library
0002 /*
0003     SPDX-FileCopyrightText: 2009 Radek Novacek <rnovacek@redhat.com>
0004     SPDX-FileCopyrightText: 2008 Daniel Nicoletti <dantti85-pk@yahoo.com.br>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "PkExample.h"
0010 
0011 #include <polkitqt1-gui-actionbutton.h>
0012 #include <polkitqt1-gui-actionbuttons.h>
0013 #include <polkitqt1-authority.h>
0014 #include <QDebug>
0015 
0016 #include <QDBusMessage>
0017 #include <QDBusConnection>
0018 
0019 using namespace PolkitQt1;
0020 using namespace PolkitQt1::Gui;
0021 
0022 PkExample::PkExample(QMainWindow *parent)
0023         : QMainWindow(parent)
0024 {
0025     setupUi(this);
0026 
0027     ActionButton *bt;
0028 
0029     // Here we create an ActionButton that is a subclass of Action
0030     // always pass a QAbstractButton pointer and action id
0031     // You can change the action id later if you want
0032     bt = new ActionButton(kickPB, "org.qt.policykit.examples.kick", this);
0033     // Here we are setting the text and icon to all four states
0034     // an action might have
0035     bt->setText("Kick!");
0036     bt->setIcon(QPixmap(":/Icons/custom-no.png"));
0037     // By using set{Yes|No|Auth}Enabled you can set the states
0038     // when the button is enabled
0039     bt->setEnabled(true, Action::No);
0040     // As ActionButton is also an Action we cast it to add to menu
0041     menuActions->addAction(qobject_cast<Action *>(bt));
0042     toolBar->addAction(qobject_cast<Action *>(bt));
0043     // this signal is emitted when the user click on the action,
0044     // it will only happen if it was inserted in a QMenu or a QToolBar
0045     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0046     // This signal was propagated from the QAbstractButton just for
0047     // convenience in this case we don't have any benefit but the code
0048     // look cleaner
0049     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0050     // this is the Action activated signal, it is always emitted whenever
0051     // someone click and get authorized to do the action
0052     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0053 
0054     bt = new ActionButton(cryPB, "org.qt.policykit.examples.cry", this);
0055     bt->setText("Cry!");
0056     bt->setIcon(QPixmap(":/Icons/custom-yes.png"));
0057     menuActions->addAction(qobject_cast<Action *>(bt));
0058     toolBar->addAction(qobject_cast<Action *>(bt));
0059     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0060     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0061     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0062 
0063     bt = new ActionButton(bleedPB, "org.qt.policykit.examples.bleed", this);
0064     bt->setText("Bleed!");
0065     bt->setIcon(QPixmap(":/Icons/action-locked-default.png"));
0066     menuActions->addAction(qobject_cast<Action *>(bt));
0067     toolBar->addAction(qobject_cast<Action *>(bt));
0068     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0069     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0070     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0071 
0072     // This action is more customized
0073     bt = new ActionButton(playPB, "org.qt.policykit.examples.play", this);
0074     bt->setText("Play!");
0075     bt->setVisible(true, Action::No | Action::Auth | Action::Yes);
0076     bt->setEnabled(true, Action::No | Action::Auth | Action::Yes);
0077     // here we set the behavior of PolKitResul = No
0078     bt->setText("Can't play!", Action::No);
0079     bt->setIcon(QPixmap(":/Icons/custom-no.png"), Action::No);
0080     bt->setToolTip("If your admin wasn't annoying, you could do this", Action::No);
0081     // here we set the behavior of PolKitResul = Auth
0082     bt->setText("Play?", Action::Auth);
0083     bt->setIcon(QPixmap(":/Icons/action-locked-default.png"), Action::Auth);
0084     bt->setToolTip("Only card carrying tweakers can do this!", Action::Auth);
0085     // here we set the behavior of PolKitResul = Yes
0086     bt->setText("Play!", Action::Yes);
0087     bt->setIcon(QPixmap(":/Icons/custom-yes.png"), Action::Yes);
0088     bt->setToolTip("Go ahead, play!", Action::Yes);
0089 
0090     menuActions->addAction(qobject_cast<Action *>(bt));
0091     toolBar->addAction(qobject_cast<Action *>(bt));
0092     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0093     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0094     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0095 
0096     bt = new ActionButton(deletePB, "org.qt.policykit.examples.delete", this);
0097     bt->setText("Delete!");
0098     bt->setIcon(QPixmap(":/Icons/custom-no.png"), Action::No);
0099     bt->setIcon(QPixmap(":/Icons/action-locked-default.png"), Action::Auth);
0100     bt->setIcon(QPixmap(":/Icons/custom-yes.png"), Action::Yes);
0101     menuActions->addAction(qobject_cast<Action *>(bt));
0102     toolBar->addAction(qobject_cast<Action *>(bt));
0103     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0104     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0105     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0106 
0107     bt = new ActionButton(listenPB, "org.qt.policykit.examples.listen", this);
0108     bt->setText("Listen!");
0109     bt->setIcon(QPixmap(":/Icons/custom-no.png"), Action::No);
0110     bt->setIcon(QPixmap(":/Icons/action-locked-default.png"), Action::Auth);
0111     bt->setIcon(QPixmap(":/Icons/custom-yes.png"), Action::Yes);
0112     menuActions->addAction(qobject_cast<Action *>(bt));
0113     toolBar->addAction(qobject_cast<Action *>(bt));
0114     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0115     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0116     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0117 
0118     bt = new ActionButton(setPB, "org.qt.policykit.examples.set", this);
0119     bt->setText("Set!");
0120     bt->setIcon(QPixmap(":/Icons/custom-no.png"), Action::No);
0121     bt->setIcon(QPixmap(":/Icons/action-locked-default.png"), Action::Auth);
0122     bt->setIcon(QPixmap(":/Icons/custom-yes.png"), Action::Yes);
0123     menuActions->addAction(qobject_cast<Action *>(bt));
0124     toolBar->addAction(qobject_cast<Action *>(bt));
0125     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0126     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0127     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0128 
0129     bt = new ActionButton(shoutPB, "org.qt.policykit.examples.shout", this);
0130     bt->setIcon(QPixmap(":/Icons/custom-no.png"), Action::No);
0131     bt->setIcon(QPixmap(":/Icons/action-locked-default.png"), Action::Auth);
0132     bt->setIcon(QPixmap(":/Icons/custom-yes.png"), Action::Yes);
0133     bt->setText("Can't shout!", Action::No);
0134     bt->setText("Shout?", Action::Auth);
0135     bt->setText("Shout!", Action::Yes);
0136     menuActions->addAction(qobject_cast<Action *>(bt));
0137     toolBar->addAction(qobject_cast<Action *>(bt));
0138     connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
0139     connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
0140     connect(bt, SIGNAL(authorized()), this, SLOT(actionActivated()));
0141 
0142     // test configChanged
0143 }
0144 
0145 PkExample::~PkExample()
0146 {
0147 }
0148 
0149 void PkExample::activateAction()
0150 {
0151     // Here we cast the sender() to an Action and call activate()
0152     // on it.
0153     // Be careful in doing the same for ActionButton won't work as expected
0154     // as action->activate() is calling Action::activate() and
0155     // not ActionButton::activate which are different.
0156     // You can cast then to ActionButton but be careful
0157     // an Action casted to ActionButton may crash you app
0158     Action *action = qobject_cast<Action *>(sender());
0159     // calling activate with winId() makes the auth dialog
0160     // be correct parented with your application.
0161     action->activate();
0162 }
0163 
0164 void PkExample::actionActivated()
0165 {
0166     // This slot is called whenever an action is allowed
0167     // here you will do your dirt job by calling a helper application
0168     // that might erase your hardrive ;)
0169     Action *action = qobject_cast<Action *>(sender());
0170 
0171     // this is our Special Action that after allowed will call the helper
0172     if (action->is("org.qt.policykit.examples.set")) {
0173         qDebug() << "toggled for: org.qt.policykit.examples.set";
0174 
0175         QDBusMessage message;
0176         message = QDBusMessage::createMethodCall("org.qt.policykit.examples",
0177                   "/",
0178                   "org.qt.policykit.examples",
0179                   QLatin1String("set"));
0180         QList<QVariant> argumentList;
0181         argumentList << QVariant::fromValue(setCB->currentText());
0182         message.setArguments(argumentList);
0183         // notice the systemBus here..
0184         QDBusMessage reply = QDBusConnection::systemBus().call(message);
0185         if (reply.type() == QDBusMessage::ReplyMessage
0186                 && reply.arguments().size() == 1) {
0187             // the reply can be anything, here we receive a bool
0188             QListWidgetItem *item;
0189             if (reply.arguments().first().toBool())
0190                 item = new QListWidgetItem(QPixmap(":/Icons/custom-yes.png"),
0191                                            QString("Implicit authorization for shout has been set to %0")
0192                                            .arg(setCB->currentText()));
0193             else
0194                 item = new QListWidgetItem(QPixmap(":/Icons/custom-no.png"),
0195                                            QString("Can't change the implicit authorization. Denied."));
0196             actionList->addItem(item);
0197             qDebug() << reply.arguments().first().toString();
0198         } else if (reply.type() == QDBusMessage::MethodCallMessage) {
0199             qWarning() << "Message did not receive a reply (timeout by message bus)";
0200         }
0201         return;
0202     }
0203 
0204     // As debug message says we are pretending to be the mechanism for the
0205     // following action, here you will actually call your DBus helper that
0206     // will run as root (setuid is not needed, see DBus docs).
0207     // In the helper application you will issue checkAuthorizationSync,
0208     // passing the action id and the caller pid (which DBus will tell you).
0209     qDebug() << "pretending to be the mechanism for action:" << action->actionId();
0210 
0211     Authority::Result result;
0212     UnixProcessSubject subject(static_cast<uint>(QCoreApplication::applicationPid()));
0213 
0214     result = Authority::instance()->checkAuthorizationSync(action->actionId(), subject,
0215              Authority::AllowUserInteraction);
0216     if (result == Authority::Yes) {
0217         // in the helper you will do the action
0218         qDebug() << "caller is authorized to do:" << action->actionId();
0219         QListWidgetItem *item = new QListWidgetItem(QPixmap(":/Icons/custom-yes.png"), action->actionId());
0220         actionList->addItem(item);
0221     } else {
0222         // OR return false to notify the caller that the action is not authorized.
0223         qDebug() << "caller is NOT authorized to do:" << action->actionId();
0224         QListWidgetItem *item = new QListWidgetItem(QIcon(":/Icons/custom-no.png"), action->actionId());
0225         actionList->addItem(item);
0226     }
0227 }