![](/img/trans.png)
[英]How to create a QML extension in C++ using CMake in Qt 6.2
[英]How to create files with root privileges using C++/Qt and PolKit-Qt-1
對於冗長的討論,我深表歉意。 另外,這是我第一次提交給 StackOverflow,所以請原諒我的不熟悉。
我通常用Linux使用C++/Qt Widget或C++/QML。這次,我需要創建或寫入具有root權限的文件,我正在使用以下URL(PolKit-Qt-1)創建和測試我自己的C++/ Qt Widget 軟件。
https://api.kde.org/polkit-qt-1/html/
我正在使用 polkit-qt-gui-1 創建軟件 (C++/Qt),以便在按下按鈕時創建和寫入具有根權限的文件。
但是會出現權限錯誤,因為該文件不能以root創建或寫入,而是以執行用戶創建或寫入。
可能是某個配置文件有誤,或者源代碼有缺失或不正確的部分。
我想在按下按鈕時創建或寫入具有 root 權限的文件。 如何使用 C++/Qt 和 PolKit-Qt-1 創建或寫入具有根權限的文件?
謝謝您的合作。
我自己的源代碼如下所示。 polkit-1 的操作文件也如下所示。
主.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
主窗口.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
PolkitQt1::Gui::ActionButton *bt = new PolkitQt1::Gui::ActionButton(ui->pushButton, "org.qt.policykit.examples.write", this);
bt->setText("Run with administrative privileges");
bt->setVisible(true, PolkitQt1::Gui::Action::No | PolkitQt1::Gui::Action::Auth | PolkitQt1::Gui::Action::Yes);
bt->setEnabled(true, PolkitQt1::Gui::Action::No | PolkitQt1::Gui::Action::Auth | PolkitQt1::Gui::Action::Yes);
connect(bt, SIGNAL(triggered(bool)), this, SLOT(activateAction()));
connect(bt, SIGNAL(clicked(QAbstractButton*,bool)), bt, SLOT(activate()));
connect(bt, SIGNAL(authorized()), this, SLOT(onBtnClicked()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::activateAction()
{
PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());
action->activate();
}
void MainWindow::onBtnClicked()
{
PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());
qDebug() << "pretending to be the mechanism for action:" << action->actionId();
PolkitQt1::UnixProcessSubject subject(static_cast<uint>(QCoreApplication::applicationPid()));
PolkitQt1::Authority::Result result = PolkitQt1::Authority::instance()->checkAuthorizationSync(action->actionId(), subject, PolkitQt1::Authority::AllowUserInteraction);
if (result == PolkitQt1::Authority::Yes)
{
// Write /opt/sample.txt file with root privilege.
writeTextFile("/opt/sample.txt", "foo bar");
}
else
{
return;
}
return;
}
void MainWindow::writeTextFile(QString FileName, QString strOutputData)
{
QFileInfo FileInfo(FileName);
QFile File(FileName);
if(!File.open(QIODevice::WriteOnly))
{
QString strErrMsg = "File(" + FileInfo.fileName() + ") Open Error: " + File.errorString();
qDebug() << strErrMsg;
return;
}
QTextStream OutStream(&File);
OutStream << strOutputData;
File.close();
return;
}
主窗口.h:
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDBusContext>
#include <QDBusMessage>
#include <QDBusConnection>
#include <polkit-qt5-1/polkitqt1-gui-action.h>
#include <polkit-qt5-1/polkitqt1-gui-actionbutton.h>
#include <polkit-qt5-1/polkitqt1-gui-actionbuttons.h>
#include <polkit-qt5-1/polkitqt1-authority.h>
#include <dbus/dbus.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow, protected QDBusContext
{
Q_OBJECT
private:
void writeTextFile(QString FileName, QString strOutputData);
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private Q_SLOTS:
void activateAction();
void onBtnClicked();
};
#endif // MAINWINDOW_H
/usr/share/polkit-1/actions/org.qt.policykit.examples.policy:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE policyconfig PUBLIC '-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN' 'http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd'>
<policyconfig>
<vendor>KDE</vendor>
<vendor_url>http://www.kde.org</vendor_url>
<action id="org.qt.policykit.examples.write">
<description>Write</description>
<message>Prevents PolKit-Qt-1 example from writing</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
</policyconfig>
抱歉讓您久等了。
經過反復試驗,以下源代碼允許程序僅在按下特定按鈕時以管理權限 (root) 運行。
請原諒有點冗長的帖子。
主要可執行文件是 GUI 軟件,通過按下按鈕發送 D-Bus 消息。
主.cpp:
main.cpp has the same source code as above.
主窗口.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onAuthBtnClicked()
{
QDBusConnection bus = QDBusConnection::systemBus();
if (!bus.isConnected())
{
QMessageBox(QMessageBox::Critical, tr("D-Bus error"), tr("Cannot connect to the D-Bus session bus."), QMessageBox::Close, this).exec();
}
// this is our Special Action that after allowed will call the helper
QDBusMessage message;
message = QDBusMessage::createMethodCall("org.qt.policykit.examples", "/", "org.qt.policykit.examples", QLatin1String("write"));
// If a method in a helper file has arguments, enter the arguments.
//QList<QVariant> ArgsToHelper;
//ArgsToHelper << QVariant::fromValue("foo") << QVariant::fromValue("bar");
//message.setArguments(ArgsToHelper);
// Send a message to DBus. (Execute the helper file.)
QDBusMessage reply = QDBusConnection::systemBus().call(message);
// Receive the return value (including arguments) from the helper file.
// The methods in the helper file have two arguments, so check them.
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().size() == 2)
{
// the reply can be anything, here we receive a bool
if (reply.arguments().at(0).toInt() == 0)
{ // If the helper file method completes successfully after successful authentication
QMessageBox(QMessageBox::NoIcon, tr("Successed"), tr("The file was written successfully."), QMessageBox::Close, this).exec();
}
else if (reply.arguments().at(0).toInt() == -1)
{ // If the helper file method fails after successful authentication
QString strErrMsg = reply.arguments().at(1).toString();
QMessageBox(QMessageBox::Critical, tr("Failed"), tr("Failed to write file.\n") + strErrMsg, QMessageBox::Close, this).exec();
}
else
{ // If the authentication is canceled
QMessageBox(QMessageBox::NoIcon, tr("Cancelled"), tr("Writing of the file was canceled."), QMessageBox::Close, this).exec();
}
}
else if (reply.type() == QDBusMessage::MethodCallMessage)
{
QMessageBox(QMessageBox::Warning, tr("Time out"), tr("Message did not receive a reply (timeout by message bus)."), QMessageBox::Close, this).exec();
}
else if (reply.type() == QDBusMessage::ErrorMessage)
{
QMessageBox(QMessageBox::Critical, tr("D-Bus error"), tr("Could not send message to D-Bus."), QMessageBox::Close, this).exec();
}
return;
}
主窗口.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QtGui>
#include <QDBusContext>
#include <QDBusMessage>
#include <QDBusConnection>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public: // Public Functions
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private: // Private Variables
Ui::MainWindow *ui;
private Q_SLOTS:
void onAuthBtnClicked();
};
#endif // MAINWINDOW_H
Helper 可執行文件是從 D-Bus 接收消息並創建具有 root 權限的文件的軟件。
主.cpp:
#include <QCoreApplication>
#include "SampleHelper.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SampleHelper sample(argc, argv);
return a.exec();
}
示例助手.cpp:
#include <QTimer>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include "SampleHelper.h"
#include "SampleAdaptor.h"
#define MINUTE 30000
SampleHelper::SampleHelper(int &argc, char **argv) : QCoreApplication(argc, argv)
{
(void) new SampleAdaptor(this);
// Register the DBus service
if (!QDBusConnection::systemBus().registerService("org.qt.policykit.examples"))
{
QTextStream ErrStream(stderr);
ErrStream << QDBusConnection::systemBus().lastError().message();
QTimer::singleShot(0, this, SLOT(quit()));
return;
}
if (!QDBusConnection::systemBus().registerObject("/", this))
{
QTextStream ErrStream(stderr);
ErrStream << "unable to register service interface to dbus";
QTimer::singleShot(0, this, SLOT(quit()));
return;
}
// Normally you will set a timeout so your application can
// free some resources of the poor client machine ;)
QTimer::singleShot(MINUTE, this, SLOT(quit()));
}
SampleHelper::~SampleHelper()
{
}
int SampleHelper::write(QString &strErrMsg)
{
// message().service() is the service name of the caller
// We can check if the caller is authorized to the following action
PolkitQt1::Authority::Result result;
PolkitQt1::SystemBusNameSubject subject(message().service());
result = PolkitQt1::Authority::instance()->checkAuthorizationSync("org.qt.policykit.examples.write", subject , PolkitQt1::Authority::AllowUserInteraction);
if (result == PolkitQt1::Authority::Yes)
{ // Caller is authorized so we can perform the action
return writeValue(strErrMsg);
}
else
{ // Caller is not authorized so the action can't be performed
return 1;
}
}
int SampleHelper::writeValue(QString &strErrMsg)
{
// This action must be authorized first. It will set the implicit
// authorization for the Shout action by editing the .policy file
try
{
QFileInfo FileInfo("/opt/sample.txt");
QFile File("/opt/sample.txt");
if(!File.open(QIODevice::WriteOnly))
{
strErrMsg = "File(" + FileInfo.fileName() + ") Open Error: " + File.errorString();
return -1;
}
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date = current_date_time.toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
QTextStream OutStream(&File);
OutStream << current_date;
File.close();
}
catch (QException &err)
{
strErrMsg = err.what();
}
return 0;
}
示例助手.h:
#ifndef SAMPLE_HELPER_H
#define SAMPLE_HELPER_H
#include <QDBusConnection>
#include <QDBusContext>
#include <QDBusMessage>
#include <QCoreApplication>
#include <polkit-qt5-1/polkitqt1-authority.h>
class SampleHelper : public QCoreApplication, protected QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qt.policykit.examples")
private:
int writeValue(QString &strErrMsg);
public:
SampleHelper(int &argc, char **argv);
~SampleHelper() override;
public Q_SLOTS:
int write(QString &strErrMsg);
};
#endif
執行qdbusxml2cpp
命令(此時使用D-Bus接口文件)為helper生成適配器源代碼文件和header文件。
qdbusxml2cpp -a SampleAdaptor -c SampleAdaptor -i SampleHelper.h -l SampleHelper org.qt.policykit.examples.xml
在此示例中,生成了 SampleAdaptor.cpp 和 SampleAdaptor.h。
將此文件添加到輔助可執行文件的項目中。
如果這是自動完成的:
Qt.pro文件,寫了如下命令。
system(qdbusxml2cpp -a SampleAdaptor -c SampleAdaptor -i SampleHelper.h -l SampleHelper org.qt.policykit.examples.xml)
CMake文件,寫了以下命令。
qt_add_dbus_adaptor(
SampleAdaptor_SRC
org.qt.policykit.examples.xml
SampleHelper.h
SampleHelper
SampleAdaptor
SampleAdaptor
)
/usr/share/polkit-1/actions/org.qt.policykit.examples.policy:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE policyconfig PUBLIC '-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN' 'http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd'>
<policyconfig>
<vendor>presire</vendor>
<vendor_url></vendor_url>
<action id="org.qt.policykit.examples.write">
<description>Write</description>
<message>Prevents PolKit-Qt-1 example from writing</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
</action>
</policyconfig>
/usr/share/dbus-1/interfaces/org.qt.policykit.examples.xml:
<!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.qt.policykit.examples">
<method name="write" >
<!-- OUT: whether the user gained the authorization -->
<arg direction="out" type="i" name="code" />
<arg direction="out" type="s" name="msg" />
</method>
</interface>
</node>
/usr/share/dbus-1/system-services/org.qt.policykit.examples.service:
[D-BUS Service]
Name=org.qt.policykit.examples
Exec=/<Path>/<to>/<Helper executable file>
User=root
/etc/dbus-1/system-local.conf:
要么
/etc/dbus-1/system.d/org.qt.policykit.examples.conf:
要么
/usr/share/dbus-1/system.d/org.qt.policykit.examples.conf:
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- This configuration file specifies the required security policies
for the PolicyKit examples to work. -->
<!-- Only user root can own the PackageKit service -->
<policy user="root">
<allow own="org.qt.policykit.examples"/>
</policy>
<!-- Allow anyone to call into the service - we'll reject callers using PolicyKit -->
<policy context="default">
<allow send_destination="org.qt.policykit.examples"/>
</policy>
</busconfig>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.