You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C++/Qt与PolKit-Qt-1创建具有root权限的文件

如何通过PolKit-Qt-1实现以root权限创建/写入文件?

我是首次在StackOverflow提问,若有不当之处请见谅。日常在Linux环境下用C++/Qt Widget或C++/QML开发,现在需要实现点击按钮时以root权限创建或写入文件,所以基于PolKit-Qt-1开发测试C++/Qt Widget程序。用polkit-qt-gui-1实现相关功能,但目前文件是以执行用户权限创建/写入,出现权限错误,怀疑是配置文件或代码有问题。希望实现点击按钮时以root权限创建或写入文件,求解决方法。


源代码与配置文件

main.cpp

#include "mainwindow.h"
#include <QApplication>
    
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   MainWindow w;
   w.show();
   return a.exec();
}

mainwindow.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;
}

mainwindow.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>

问题分析与解决方法

核心问题:PolKit只是权限授权机制,不是直接的权限提升工具。你当前的代码仅完成了权限校验,但写入文件的操作仍在当前用户进程中执行,并未切换到root权限。要实现root权限的文件操作,有两种可行方案:

方案一:用pkexec启动独立辅助进程执行写入

PolKit配合pkexec可以让你以root身份启动专门的工具程序,由它完成文件写入,步骤如下:

  1. 编写独立的文件写入工具filewriter:
// filewriter.cpp
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    if (argc != 3) {
        qDebug() << "Usage:" << argv[0] << "<file_path>" << "<content>";
        return 1;
    }

    QString filePath = argv[1];
    QString content = argv[2];

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly)) {
        qDebug() << "Failed to open file:" << file.errorString();
        return 1;
    }

    QTextStream out(&file);
    out << content;
    file.close();

    return 0;
}

编译并安装:

g++ -o filewriter filewriter.cpp -lQt5Core
sudo install -m 755 filewriter /usr/local/bin/
  1. 修改主程序onBtnClicked函数,调用pkexec执行工具:
void MainWindow::onBtnClicked()
{
    PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());

    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)
    {
        QProcess process;
        process.start("pkexec", {"/usr/local/bin/filewriter", "/opt/sample.txt", "foo bar"});
        process.waitForFinished();
        if (process.exitCode() != 0) {
            qDebug() << "File write failed:" << process.readAllStandardError();
        }
    }
}
  1. 更新PolKit配置文件,允许pkexec调用该工具:
    修改/usr/share/polkit-1/actions/org.qt.policykit.examples.policy的<action>节点:
<action id="org.qt.policykit.examples.write">
    <description>Write file as root</description>
    <message>需要权限以root身份写入系统文件</message>
    <defaults>
        <allow_inactive>no</allow_inactive>
        <allow_active>auth_admin_keep</allow_active>
    </defaults>
    <annotate key="org.freedesktop.policykit.exec.path">/usr/local/bin/filewriter</annotate>
    <annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
</action>

方案二:通过root权限的DBus服务执行写入

适合复杂操作场景,需要编写一个运行在root权限下的DBus服务,主程序授权后调用服务完成写入:

  1. 编写DBus接口定义org.example.FileWriter.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.example.FileWriter">
    <method name="WriteFile">
      <arg type="s" name="filePath" direction="in"/>
      <arg type="s" name="content" direction="in"/>
      <arg type="b" name="success" direction="out"/>
    </method>
  </interface>
</node>
  1. 生成DBus适配代码并编写服务程序:
qdbusxml2cpp -c FileWriterAdaptor -a org.example.FileWriter.h:org.example.FileWriter.cpp org.example.FileWriter.xml
// filewriter_service.cpp
#include <QCoreApplication>
#include <QDBusConnection>
#include <QFile>
#include <QTextStream>
#include "org.example.FileWriter.h"

class FileWriterAdaptor : public org::example::FileWriterAdaptor, public QObject
{
    Q_OBJECT
public:
    FileWriterAdaptor(QObject *parent) : org::example::FileWriterAdaptor(parent) {}

public slots:
    bool WriteFile(const QString &filePath, const QString &content) {
        QFile file(filePath);
        if (!file.open(QIODevice::WriteOnly)) {
            return false;
        }
        QTextStream out(&file);
        out << content;
        file.close();
        return true;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QDBusConnection bus = QDBusConnection::systemBus();
    if (!bus.registerService("org.example.FileWriter")) {
        qDebug() << "Failed to register service:" << bus.lastError().message();
        return 1;
    }

    QObject obj;
    new FileWriterAdaptor(&obj);
    if (!bus.registerObject("/org/example/FileWriter", &obj)) {
        qDebug() << "Failed to register object:" << bus.lastError().message();
        return 1;
    }

    return a.exec();
}

编译安装:

g++ -o filewriter_service filewriter_service.cpp org.example.FileWriter.cpp -lQt5Core -lQt5DBus
sudo install -m 755 filewriter_service /usr/local/bin/
  1. 创建systemd服务文件/etc/systemd/system/filewriter.service:
[Unit]
Description=File Writer DBus Service

[Service]
ExecStart=/usr/local/bin/filewriter_service
User=root

[Install]
WantedBy=multi-user.target

启动并启用服务:

sudo systemctl daemon-reload
sudo systemctl start filewriter.service
sudo systemctl enable filewriter.service
  1. 修改主程序onBtnClicked函数调用DBus服务:
void MainWindow::onBtnClicked()
{
    PolkitQt1::Gui::Action *action = qobject_cast<PolkitQt1::Gui::Action *>(sender());

    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)
    {
        QDBusInterface interface("org.example.FileWriter", "/org/example/FileWriter", "org.example.FileWriter", QDBusConnection::systemBus());
        QDBusReply<bool> reply = interface.call("WriteFile", "/opt/sample.txt", "foo bar");
        if (!reply.isValid()) {
            qDebug() << "DBus call failed:" << reply.error().message();
        } else {
            qDebug() << "File write success:" << reply.value();
        }
    }
}
  1. 更新PolKit配置文件,允许调用该DBus服务:
    在org.qt.policykit.examples.policy的<action>节点中添加:
<annotate key="org.freedesktop.policykit.dbus.name">org.example.FileWriter</annotate>
<annotate key="org.freedesktop.policykit.dbus.path">/org/example/FileWriter</annotate>
<annotate key="org.freedesktop.policykit.dbus.interface">org.example.FileWriter</annotate>
<annotate key="org.freedesktop.policykit.dbus.method">WriteFile</annotate>

额外注意事项

  • 确保PolKit配置文件权限正确:sudo chmod 644 /usr/share/polkit-1/actions/org.qt.policykit.examples.policy
  • 测试前重启PolKit服务:sudo systemctl restart polkit.service
  • 不要尝试在主进程中直接提升权限,不符合PolKit设计理念且存在安全风险

内容的提问来源于stack exchange,提问作者presire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:30:45