之前项目中遇到了一个问题,非管理员权限的用户登录桌面系统之后,也需要进行一些需要root权限的操作,而出于安全方面的考虑,无法直接将用户加入root组,那么桌面系统的源码中就需要使用到KDE提供的提权功能。KDE提供的提权功能可以给指定的自定义操作函数提供等同于root的权限。kde提权操作,需要用到KAuth模块。对这个实现流程做一个记录,方便后续查看。
首先是usermanage.actions文件,actions文件是指明需要进行提权操作的函数接口,其中需要着重关注的,是[org.kde.auth.usermanage.read]中的read,此名称必须与后续编写的提权函数名称完全相同,[org.kde.auth.usermanage.write]和[org.kde.auth.usermanage.longaction]中的write、longaction同理。Name和Description自定义。
[Domain]
Name=Auth_Example
Icon=utilities-terminal
[org.kde.auth.usermanage.read]
Name=Example read action
Description=The system is attempting to perform the read action
Policy=yes
[org.kde.auth.usermanage.write]
Name=Example write action
Description=The system is attempting to perform the write action
Policy=yes
[org.kde.auth.usermanage.longaction]
Name=Example longaction
Description=The longaction
Policy=yes
CMakeLists.txt文件如下,着重关注末尾几行:
project(UserManageHelper)
cmake_minimum_required(VERSION 2.8.12)
################# Disallow in-source build #################
#if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
# message(FATAL_ERROR "plasma-settings requires an out of source build. Please create a separate build directory and run 'cmake path_to_plasma-settings [options]' there.")
#endif()
#include(CPack)
#include(FeatureSummary)
#find_package(PkgConfig)
################# set KDE specific information #################
find_package(ECM 0.0.8 REQUIRED NO_MODULE)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
#include(ECMQMLModules)
find_package(Qt5 REQUIRED NO_MODULE COMPONENTS Core)
################# now find all used packages #################
set (QT_MIN_VERSION "5.4.0")
find_package(KF5Auth NO_MODULE)
find_package(Qt5 5.10.1 CONFIG REQUIRED COMPONENTS
Core
)
add_executable(usermanagehelper UserManageHelper.cpp)
target_link_libraries(usermanagehelper Qt5::Core KF5::Auth)
install(TARGETS usermanagehelper DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
kauth_install_actions(org.kde.auth.usermanage usermanage.actions)
kauth_install_helper_files(usermanagehelper org.kde.auth.usermanage root)
set_target_properties(usermanagehelper PROPERTIES COMPILE_FLAGS "-Wall -ggdb")
代码的编写就很简单了,继承QObject,实现几个槽函数,这个槽函数的名称和actions文件中是对应的:
#undef QT_NO_CAST_FROM_ASCII
#include "grp.h"
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <QFile>
#include <QTextStream>
#include <QThread>
//! [helper_declaration]
#include <kauth.h> // 提权操作所必须包含的头文件
#include <QObject>
#include <iostream>
using namespace KAuth;
class UserManageHelper : public QObject
{
Q_OBJECT
public:
UserManageHelper();
public Q_SLOTS:
ActionReply read(const QVariantMap& args); // 提权操作通用函数原型
ActionReply write(const QVariantMap& args);
ActionReply longaction(const QVariantMap& args);
};
UserManageHelper::UserManageHelper()
{
}
ActionReply UserManageHelper::read(const QVariantMap& args)
{
ActionReply reply;
QString newfilename = args["newfilename"].toString(); // 取出参数
QString oldfilename = args["oldfilename"].toString();
…… // 实现自定义操作
return reply;
}
//! [helper_read_action]
ActionReply UserManageHelper::write(const QVariantMap &args)
{
// Q_UNUSED(args)
// return ActionReply::SuccessReply();
ActionReply reply;
……
return reply;
}
//! [helper_longaction]
ActionReply UserManageHelper::longaction(const QVariantMap &args)
{
……
return ActionReply::SuccessReply();
}
// 这里需要注意,这里需要替换成实际的名称
KAUTH_HELPER_MAIN("org.kde.auth.usermanage", UserManageHelper)
#include "UserManageHelper.moc"
编译完成后,build目录下除了常规的cmake生成文件以外,需要关注的生成文件还有org.kde.auth.usermanage.conf、org.kde.auth.usermanage.policy和org.kde.auth.usermanage.service。将这三个文件和生成可执行文件拷贝到指定路径,然后添加权限,即可完全提权操作的安装配置。
\cp UserManageHelper/build/usermanagehelper /usr/libexec/kf5/kauth/usermanagehelper
\cp UserManageHelper/build/org.kde.auth.usermanage.policy /usr/share/polkit-1/actions/org.kde.auth.usermanage.policy
\cp UserManageHelper/build/org.kde.auth.usermanage.conf /etc/dbus-1/system.d/org.kde.auth.usermanage.conf
\cp UserManageHelper/build/org.kde.auth.usermanage.service /usr/share/dbus-1/system-services/org.kde.auth.usermanage.service
sudo chmod 755 /usr/libexec/kf5/kauth/usermanagehelper
示例的调用代码如下:
……
#include <KJob>
#include <KIO/CopyJob>
#include <KIconLoader>
#include <KUser>
……
QVariantMap args;
args["newfilename"] = group_filename; // 设定参数,也就是提权函数中取出的参数
args["oldfilename"] = new_group_filename;
Action readAction(QLatin1String("org.kde.auth.usermanage.read"));
readAction.setHelperId(QLatin1String("org.kde.auth.usermanage"));
readAction.setArguments(args);
ExecuteJob *job = readAction.execute();
if (!job->exec()) {
int error = job->error();
qDebug() << "KAuth returned an error code:" << job->error();
} else {
QVariantMap map = job->data();
QString contents = job->data()["contents"].toString();
}
https://www.twblogs.net/a/5bf2f67dbd9eee04040a7e60/?lang=zh-cn