parent
0a9d408a78
commit
9c88f3c1ca
@ -0,0 +1,8 @@ |
||||
cmake_minimum_required(VERSION 3.7) |
||||
|
||||
project(dp4-uos) |
||||
|
||||
add_subdirectory(dp4-login-plugin) |
||||
add_subdirectory(dp4-pam) |
||||
add_subdirectory(dp4-dbus-service) |
||||
add_subdirectory(example) |
||||
@ -0,0 +1,97 @@ |
||||
# - Try to find the PAM libraries |
||||
# Once done this will define |
||||
# |
||||
# PAM_FOUND - system has pam |
||||
# PAM_INCLUDE_DIR - the pam include directory |
||||
# PAM_LIBRARIES - libpam library |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions |
||||
# are met: |
||||
# |
||||
# 1. Redistributions of source code must retain the copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# 2. Redistributions in binary form must reproduce the copyright |
||||
# notice, this list of conditions and the following disclaimer in the |
||||
# documentation and/or other materials provided with the distribution. |
||||
# 3. The name of the author may not be used to endorse or promote products |
||||
# derived from this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
if (PAM_INCLUDE_DIR AND PAM_LIBRARY) |
||||
# Already in cache, be silent |
||||
set(PAM_FIND_QUIETLY TRUE) |
||||
endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) |
||||
|
||||
find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h) |
||||
find_library(PAM_LIBRARY pam) |
||||
find_library(DL_LIBRARY dl) |
||||
|
||||
if (PAM_INCLUDE_DIR AND PAM_LIBRARY) |
||||
set(PAM_FOUND TRUE) |
||||
if (DL_LIBRARY) |
||||
set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY}) |
||||
else (DL_LIBRARY) |
||||
set(PAM_LIBRARIES ${PAM_LIBRARY}) |
||||
endif (DL_LIBRARY) |
||||
|
||||
if (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) |
||||
# darwin claims to be something special |
||||
set(HAVE_PAM_PAM_APPL_H 1) |
||||
endif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h) |
||||
|
||||
if (NOT DEFINED PAM_MESSAGE_CONST) |
||||
include(CheckCXXSourceCompiles) |
||||
# XXX does this work with plain c? |
||||
check_cxx_source_compiles(" |
||||
#if ${HAVE_PAM_PAM_APPL_H}+0 |
||||
# include <pam/pam_appl.h> |
||||
#else |
||||
# include <security/pam_appl.h> |
||||
#endif |
||||
|
||||
static int PAM_conv( |
||||
int num_msg, |
||||
const struct pam_message **msg, /* this is the culprit */ |
||||
struct pam_response **resp, |
||||
void *ctx) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int main(void) |
||||
{ |
||||
struct pam_conv PAM_conversation = { |
||||
&PAM_conv, /* this bombs out if the above does not match */ |
||||
0 |
||||
}; |
||||
|
||||
return 0; |
||||
} |
||||
" PAM_MESSAGE_CONST) |
||||
endif (NOT DEFINED PAM_MESSAGE_CONST) |
||||
set(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL "PAM expects a conversation function with const pam_message") |
||||
|
||||
endif (PAM_INCLUDE_DIR AND PAM_LIBRARY) |
||||
|
||||
if (PAM_FOUND) |
||||
if (NOT PAM_FIND_QUIETLY) |
||||
message(STATUS "Found PAM: ${PAM_LIBRARIES}") |
||||
endif (NOT PAM_FIND_QUIETLY) |
||||
else (PAM_FOUND) |
||||
if (PAM_FIND_REQUIRED) |
||||
message(FATAL_ERROR "PAM was not found") |
||||
endif(PAM_FIND_REQUIRED) |
||||
endif (PAM_FOUND) |
||||
|
||||
mark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST) |
||||
@ -0,0 +1,5 @@ |
||||
dp4-uos (1.0.0) unstable; urgency=medium |
||||
|
||||
* support single sign-on |
||||
|
||||
-- donghualin <donghualin@uniontech.com> Thu, 16 May 2024 11:07:48 +0800 |
||||
@ -0,0 +1 @@ |
||||
9 |
||||
@ -0,0 +1,30 @@ |
||||
Source: dp4-uos |
||||
Section: libs |
||||
Priority: optional |
||||
Maintainer: Deepin Packages Builder <packages@deepin.com> |
||||
Build-Depends: debhelper (>= 8.0.0), |
||||
cmake, |
||||
qt5-default, |
||||
pkg-config, |
||||
dde-session-shell-dev, |
||||
qtbase5-dev, |
||||
qtbase5-private-dev, |
||||
qttools5-dev, |
||||
libpam0g-dev |
||||
Standards-Version: 4.5.1 |
||||
Homepage: https://www.deepin.org |
||||
|
||||
Package: deepin-service-plugin-dp4 |
||||
Architecture: any |
||||
Depends: ${shlibs:Depends}, ${misc:Depends} |
||||
Description: the service of dp4. |
||||
|
||||
Package: login-dp4-plugin |
||||
Architecture: any |
||||
Depends: ${shlibs:Depends}, ${misc:Depends} |
||||
Description: the plugin of login by dp4. |
||||
|
||||
Package: pam-dp4 |
||||
Architecture: any |
||||
Depends: ${shlibs:Depends}, ${misc:Depends} |
||||
Description: the package of dp4 for login by pam. |
||||
@ -0,0 +1,20 @@ |
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ |
||||
Upstream-Name: deepin-passkey |
||||
Files: * |
||||
Copyright: 2023 Deepin Technology Co., Ltd. |
||||
License: GPL-3+ |
||||
This package 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 3 of the License, or |
||||
(at your option) any later version. |
||||
. |
||||
This package 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 General Public License for more details. |
||||
. |
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/> |
||||
. |
||||
On Debian systems, the complete text of the GNU General |
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". |
||||
@ -0,0 +1,4 @@ |
||||
usr/lib/*/deepin-service-manager/libdp4-service.so |
||||
usr/share/deepin-service-manager/user/plugin-dp4-service.json |
||||
usr/share/dbus-1/system.d/org.deepin.service.dp4.conf |
||||
usr/share/dp4-service/translations |
||||
@ -0,0 +1,2 @@ |
||||
usr/lib/dde-session-shell/modules/libdp4-login-plugin.so |
||||
usr/share/dp4-login-plugin/translations |
||||
@ -0,0 +1 @@ |
||||
usr/lib/*/security |
||||
@ -0,0 +1,6 @@ |
||||
#!/usr/bin/make -f |
||||
|
||||
include /usr/share/dpkg/default.mk |
||||
|
||||
%: |
||||
dh $@ --buildsystem=cmake |
||||
@ -0,0 +1 @@ |
||||
3.0 (native) |
||||
@ -0,0 +1,57 @@ |
||||
cmake_minimum_required(VERSION 3.7) |
||||
|
||||
set(PLUGIN_NAME "dp4-service") |
||||
|
||||
project(${PLUGIN_NAME}) |
||||
|
||||
set(CMAKE_AUTOMOC ON) |
||||
set(CMAKE_AUTORCC ON) |
||||
|
||||
include(GNUInstallDirs) |
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||
ADD_DEFINITIONS(-DQM_FILES_DIR="${CMAKE_BINARY_DIR}/dp4-service-plugin") |
||||
else() |
||||
ADD_DEFINITIONS(-DQM_FILES_DIR="/usr/share/deepin-service-manager/dp4-service-plugin/translations") |
||||
endif() |
||||
|
||||
find_package(Qt5 COMPONENTS Core Widgets DBus Network LinguistTools REQUIRED) |
||||
|
||||
file(GLOB TS_FILES "translations/*.ts") |
||||
qt5_add_translation(QM_FILES ${TS_FILES}) |
||||
add_custom_target(${PLUGIN_NAME}_language ALL DEPENDS ${QM_FILES}) |
||||
|
||||
file(GLOB_RECURSE SRCS "*.h" "*.cpp") |
||||
|
||||
add_library(${PLUGIN_NAME} MODULE |
||||
${SRCS} |
||||
) |
||||
|
||||
target_include_directories(${PLUGIN_NAME} PUBLIC |
||||
Qt5::Core |
||||
Qt5::DBus |
||||
${Qt5Widget_INCLUDE_DIRS} |
||||
${Qt5Network_INCLUDE_DIRS} |
||||
${DtkCore_INCLUDE_DIRS} |
||||
. |
||||
) |
||||
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE |
||||
Qt5::Core |
||||
Qt5::DBus |
||||
${Qt5Network_LIBRARIES} |
||||
${Qt5Widgets_LIBRARIES} |
||||
) |
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||
EXECUTE_PROCESS(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/share/system/) |
||||
EXECUTE_PROCESS(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/share/user/) |
||||
EXECUTE_PROCESS(COMMAND cp -f ${CMAKE_CURRENT_SOURCE_DIR}/plugin-dp4-service.json ${CMAKE_BINARY_DIR}/share/user/) |
||||
else() |
||||
# just need this in your project |
||||
install(TARGETS ${PLUGIN_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/deepin-service-manager/) |
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/plugin-dp4-service.json DESTINATION share/deepin-service-manager/user/) |
||||
endif() |
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.deepin.service.dp4.conf DESTINATION share/dbus-1/system.d/) |
||||
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PLUGIN_NAME}/translations) |
||||
@ -0,0 +1,23 @@ |
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "dp4service.h" |
||||
|
||||
using namespace dp4::service; |
||||
|
||||
Dp4Service::Dp4Service(QObject *parent) |
||||
: QObject(parent) |
||||
{ |
||||
QString test = tr("test"); |
||||
} |
||||
|
||||
QString Dp4Service::getToken() |
||||
{ |
||||
return m_token; |
||||
} |
||||
|
||||
void Dp4Service::setToken(const QString &token) |
||||
{ |
||||
m_token = token; |
||||
} |
||||
@ -0,0 +1,34 @@ |
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SESSIONSERVICE_H |
||||
#define SESSIONSERVICE_H |
||||
|
||||
#include <QObject> |
||||
|
||||
namespace dp4 { |
||||
namespace service { |
||||
|
||||
class Dp4Service : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
Q_CLASSINFO("D-Bus Interface", "org.deepin.service.dp4") |
||||
|
||||
Q_PROPERTY(QString token READ getToken WRITE setToken) |
||||
|
||||
public: |
||||
explicit Dp4Service(QObject *parent = nullptr); |
||||
|
||||
private: |
||||
QString getToken(); |
||||
void setToken(const QString &token); |
||||
|
||||
private: |
||||
QString m_token; |
||||
}; |
||||
|
||||
} |
||||
} |
||||
|
||||
#endif // SERVICE_H
|
||||
@ -0,0 +1,8 @@ |
||||
#!/bin/bash |
||||
if [ ! -d "translations/" ];then |
||||
mkdir translations |
||||
fi |
||||
cd ./translations |
||||
rm -f dp4-dbus-service.ts |
||||
lupdate ../ -ts -no-ui-lines -locations none -no-obsolete dp4-dbus-service.ts |
||||
cd ../ |
||||
@ -0,0 +1,19 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- --> |
||||
|
||||
<!DOCTYPE busconfig PUBLIC |
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" |
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> |
||||
<busconfig> |
||||
|
||||
<!-- Only root can own the service --> |
||||
<policy user="root"> |
||||
<allow own="org.deepin.service.dp4"/> |
||||
<allow send_destination="org.deepin.service.dp4"/> |
||||
</policy> |
||||
|
||||
<!-- Allow anyone to invoke methods on the interfaces --> |
||||
<policy context="default"> |
||||
<allow send_destination="org.deepin.service.dp4"/> |
||||
</policy> |
||||
|
||||
</busconfig> |
||||
@ -0,0 +1,13 @@ |
||||
{ |
||||
"name": "org.deepin.service.dp4", |
||||
"libPath": "libdp4-service.so", |
||||
"group": "core", |
||||
"policyStartType": "Resident", |
||||
"pluginType": "qt", |
||||
"startDelay": 0, |
||||
"policy": [ |
||||
{ |
||||
"path": "/org/deepin/service/dp4" |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,34 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#include "dp4service.h" |
||||
|
||||
#include <QDBusConnection> |
||||
#include <QDebug> |
||||
|
||||
#include <unistd.h> |
||||
|
||||
static dp4::service::Dp4Service *serviceObject = nullptr; |
||||
|
||||
extern "C" int DSMRegister(const char *name, void *data) |
||||
{ |
||||
QDBusConnection::RegisterOptions opts = QDBusConnection::ExportAllSlots |
||||
| QDBusConnection::ExportAllSignals | QDBusConnection::ExportAllProperties; |
||||
|
||||
QString path = name; |
||||
path = QString("/%1").arg(path.replace(".", "/")); |
||||
auto connection = reinterpret_cast<QDBusConnection *>(data); |
||||
serviceObject = new dp4::service::Dp4Service; |
||||
connection->registerObject(path, serviceObject, opts); |
||||
return 0; |
||||
} |
||||
|
||||
// 该函数用于资源释放
|
||||
// 非常驻插件必须实现该函数,以防内存泄漏
|
||||
extern "C" int DSMUnRegister(const char *name, void *data) |
||||
{ |
||||
(void)name; |
||||
(void)data; |
||||
serviceObject->deleteLater(); |
||||
return 0; |
||||
} |
||||
@ -0,0 +1,37 @@ |
||||
cmake_minimum_required(VERSION 3.7) |
||||
|
||||
set(LIB_NAME "dp4-login-plugin") |
||||
|
||||
project(${LIB_NAME}) |
||||
|
||||
include(GNUInstallDirs) |
||||
|
||||
# 启用 qt moc 的支持 |
||||
set(CMAKE_AUTOMOC ON) |
||||
|
||||
find_package(Qt5 COMPONENTS Core Widgets DBus Network LinguistTools REQUIRED) |
||||
find_package(PkgConfig REQUIRED) |
||||
find_package(DdeSessionShell REQUIRED) |
||||
|
||||
pkg_check_modules(SSL REQUIRED IMPORTED_TARGET libcrypto libssl openssl) |
||||
|
||||
file(GLOB TS_FILES "translations/*.ts") |
||||
qt5_add_translation(QM_FILES ${TS_FILES}) |
||||
add_custom_target(${BIN_NAME}_language ALL DEPENDS ${QM_FILES}) |
||||
|
||||
file(GLOB_RECURSE SRCS "*.h" "*.cpp") |
||||
|
||||
add_library(${LIB_NAME} SHARED ${SRCS}) |
||||
|
||||
target_include_directories(${LIB_NAME} PUBLIC |
||||
${Qt5DBus_INCLUDE_DIRS} |
||||
${DDESESSIONSHELL_INCLUDE_DIR} |
||||
) |
||||
|
||||
target_link_libraries(${LIB_NAME} PRIVATE |
||||
${Qt5Widgets_LIBRARIES} |
||||
${Qt5DBus_LIBRARIES} |
||||
) |
||||
|
||||
install(TARGETS ${LIB_NAME} LIBRARY DESTINATION lib/dde-session-shell/modules)# 安装.qm文件 |
||||
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/${LIB_NAME}/translations/) |
||||
@ -0,0 +1,97 @@ |
||||
// SPDX-FileCopyrightText: 2015 - 2022 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#include "dp4_login_module.h" |
||||
|
||||
namespace dss |
||||
{ |
||||
namespace module |
||||
{ |
||||
|
||||
Dp4LoginModule::Dp4LoginModule(QObject *parent) |
||||
: QObject(parent) |
||||
, m_callbackFun(nullptr) |
||||
, m_callbackData(new AuthCallbackData) |
||||
, m_messageCallbackFunc(nullptr) |
||||
{ |
||||
setObjectName(QStringLiteral("AssistLoginModule")); |
||||
|
||||
QString testText = tr("test"); |
||||
// 以下部分爲測試代碼,具體如何寫請根據實際的業務來處理即可
|
||||
/*m_callbackData->account = "uos";
|
||||
m_callbackData->token = "1"; |
||||
m_callbackData->result = 0; |
||||
*/ |
||||
} |
||||
|
||||
Dp4LoginModule::~Dp4LoginModule() |
||||
{ |
||||
if (m_callbackData) { |
||||
delete m_callbackData; |
||||
} |
||||
} |
||||
|
||||
void Dp4LoginModule::init() |
||||
{ |
||||
} |
||||
|
||||
QWidget *Dp4LoginModule::content() |
||||
{ |
||||
return nullptr; |
||||
} |
||||
|
||||
void Dp4LoginModule::reset() |
||||
{ |
||||
init(); |
||||
} |
||||
|
||||
void Dp4LoginModule::setCallback(LoginCallBack *callback) |
||||
{ |
||||
m_callback = callback; |
||||
m_callbackFun = callback->authCallbackFun; |
||||
} |
||||
|
||||
std::string Dp4LoginModule::onMessage(const std::string &message) |
||||
{ |
||||
qInfo() << Q_FUNC_INFO; |
||||
QJsonParseError jsonParseError; |
||||
const QJsonDocument messageDoc = QJsonDocument::fromJson(QByteArray::fromStdString(message), &jsonParseError); |
||||
if (jsonParseError.error != QJsonParseError::NoError || messageDoc.isEmpty()) { |
||||
qWarning() << Q_FUNC_INFO << "Failed to obtain message from shell!: " << QString::fromStdString(message); |
||||
return ""; |
||||
} |
||||
|
||||
QJsonObject retObj; |
||||
retObj["Code"] = 0; |
||||
retObj["Message"] = "Success"; |
||||
|
||||
QJsonObject msgObj = messageDoc.object(); |
||||
QString cmdType = msgObj.value("CmdType").toString(); |
||||
QJsonObject data = msgObj.value("Data").toObject(); |
||||
qInfo() << "Cmd type: " << cmdType; |
||||
if (cmdType == "CurrentUserChanged") { |
||||
|
||||
} else if (cmdType == "GetConfigs") { |
||||
QJsonObject retDataObj; |
||||
retDataObj["ShowAvatar"] = false; |
||||
retDataObj["ShowUserName"] = false; |
||||
retDataObj["ShowSwitchButton"] = false; |
||||
retDataObj["ShowLockButton"] = false; |
||||
retDataObj["DefaultAuthLevel"] = DefaultAuthLevel::StrongDefault; |
||||
retDataObj["AuthType"] = AuthType::AT_Custom; |
||||
|
||||
retObj["Data"] = retDataObj; |
||||
} else if (cmdType == "StartAuth") { |
||||
|
||||
} else if (cmdType == "AuthState") { |
||||
|
||||
} else if (cmdType == "LimitsInfo") { |
||||
} |
||||
|
||||
QJsonDocument doc; |
||||
doc.setObject(retObj); |
||||
return doc.toJson().toStdString(); |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,44 @@ |
||||
// SPDX-FileCopyrightText: 2015 - 2022 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef ASSIST_LOGIN_MODULE_H |
||||
#define ASSIST_LOGIN_MODULE_H |
||||
|
||||
#include "login_module_interface.h" |
||||
|
||||
namespace dss |
||||
{ |
||||
namespace module |
||||
{ |
||||
class Dp4LoginModule: public QObject, public LoginModuleInterface |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
Q_PLUGIN_METADATA(IID "com.deepin.dde.shell.Modules.Login" FILE "login.json") |
||||
Q_INTERFACES(dss::module::LoginModuleInterface) |
||||
|
||||
public: |
||||
explicit Dp4LoginModule(QObject *parent = nullptr); |
||||
~Dp4LoginModule() override; |
||||
|
||||
void init() override; |
||||
ModuleType type() const override |
||||
{ return IpcAssistLoginType; } |
||||
inline QString key() const override |
||||
{ return "dp4-login"; } |
||||
QWidget *content() override; |
||||
void setCallback(LoginCallBack *callback) override; |
||||
std::string onMessage(const std::string &) override; |
||||
void reset() override; |
||||
|
||||
private: |
||||
LoginCallBack *m_callback; |
||||
AuthCallbackFun m_callbackFun; |
||||
AuthCallbackData *m_callbackData; |
||||
MessageCallbackFun m_messageCallbackFunc; |
||||
}; |
||||
|
||||
} |
||||
} |
||||
#endif //ASSIST_LOGIN_MODULE_H
|
||||
@ -0,0 +1,4 @@ |
||||
{ |
||||
"api": "1.2.0", |
||||
"pluginType": "Login" |
||||
} |
||||
@ -0,0 +1,8 @@ |
||||
#!/bin/bash |
||||
if [ ! -d "translations/" ];then |
||||
mkdir translations |
||||
fi |
||||
cd ./translations |
||||
rm -f dp4-login-plugin.ts |
||||
lupdate ../ -ts -no-ui-lines -locations none -no-obsolete dp4-login-plugin.ts |
||||
cd ../ |
||||
@ -0,0 +1,20 @@ |
||||
cmake_minimum_required(VERSION 3.7) |
||||
|
||||
set(PAM_LIB_NAME "dp4-login-pam") |
||||
|
||||
file(GLOB_RECURSE LIB_SRCS |
||||
"*.h" |
||||
"*.c" |
||||
) |
||||
|
||||
add_library(${PAM_LIB_NAME} MODULE |
||||
${LIB_SRCS} |
||||
) |
||||
|
||||
set_target_properties(${PAM_LIB_NAME} PROPERTIES PREFIX "") |
||||
|
||||
target_link_libraries(${PAM_LIB_NAME} PRIVATE |
||||
-lpam |
||||
) |
||||
|
||||
install(TARGETS ${PAM_LIB_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/security) |
||||
@ -0,0 +1,41 @@ |
||||
#include <stdio.h> |
||||
#include <security/_pam_types.h> |
||||
#include <security/pam_modules.h> |
||||
#include <security/pam_ext.h> |
||||
#include <sys/syslog.h> |
||||
|
||||
// PAM 认证函数
|
||||
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) |
||||
{ |
||||
// 获取用户名
|
||||
const char *username = NULL; |
||||
int nret = pam_get_item(pamh, PAM_USER, (const void **)&username); |
||||
pam_syslog(pamh, LOG_WARNING, "in test login,get username..%s..ret:%d.....", username, nret); |
||||
if (nret != PAM_SUCCESS) { |
||||
return PAM_AUTH_ERR; |
||||
} |
||||
|
||||
// 获取密码
|
||||
const char *password = NULL; |
||||
int retpwd = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); |
||||
if (retpwd == PAM_SUCCESS) { |
||||
pam_syslog(pamh, LOG_WARNING, "password: %s", password); |
||||
} else { |
||||
pam_syslog(pamh, LOG_WARNING, "get password failed: %d", retpwd); |
||||
} |
||||
|
||||
for (int i = 0; i < argc; i++) { |
||||
pam_syslog(pamh, LOG_WARNING, "input parameter: %s", argv[i]); |
||||
} |
||||
return PAM_SUCCESS; |
||||
} |
||||
|
||||
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) |
||||
{ |
||||
pam_syslog(pamh, LOG_WARNING, "in test login,pam_sm_setcred...., flags:%d, argc:%d", flags, argc); |
||||
for (int i = 0; i < argc; i++) { |
||||
pam_syslog(pamh, LOG_WARNING, "input parameter: %s", argv[i]); |
||||
} |
||||
|
||||
return PAM_SUCCESS; |
||||
} |
||||
@ -0,0 +1,61 @@ |
||||
cmake_minimum_required(VERSION 3.7) |
||||
|
||||
project(example) |
||||
|
||||
include(GNUInstallDirs) |
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) |
||||
set(CMAKE_INSTALL_PREFIX /usr) |
||||
endif () |
||||
|
||||
set(CMAKE_CXX_STANDARD 11) |
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON) |
||||
set(CMAKE_PREFIX_PATH $ENV{Qt5_DIR}) |
||||
set(CMAKE_AUTOMOC ON) |
||||
set(CMAKE_AUTORCC ON) |
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall") |
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) |
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||
ADD_DEFINITIONS(-DSERVICE_CONFIG_DIR="${CMAKE_BINARY_DIR}/share/") |
||||
ADD_DEFINITIONS(-DSERVICE_LIB_DIR="${CMAKE_BINARY_DIR}/network-service-plugin/") |
||||
else() |
||||
ADD_DEFINITIONS(-DSERVICE_CONFIG_DIR="${CMAKE_INSTALL_PREFIX}/share/deepin-service-manager/") |
||||
ADD_DEFINITIONS(-DSERVICE_LIB_DIR="${CMAKE_INSTALL_FULL_LIBDIR}/deepin-service-manager/") |
||||
endif() |
||||
|
||||
file(GLOB_RECURSE COMPILEFILES *.h *.cpp ../dp4-login-plugin/*.h ../dp4-login-plugin/*.cpp) |
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug") |
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fsanitize=address -O0") |
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -O0") |
||||
endif() |
||||
|
||||
add_executable(${PROJECT_NAME} ${COMPILEFILES}) |
||||
|
||||
find_package(PAM REQUIRED) |
||||
find_package(Qt5 COMPONENTS Core Widgets DBus Network REQUIRED) |
||||
find_package(DdeSessionShell REQUIRED) |
||||
|
||||
set(TRY_KF5_LIBRARIES |
||||
IMPORTED_LOCATION_DEBIAN |
||||
IMPORTED_LOCATION_NOCONFIG |
||||
) |
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC |
||||
./service |
||||
../dp4-login-plugin/ |
||||
${PAM_INCLUDE_DIR} |
||||
${Qt5Widget_INCLUDE_DIRS} |
||||
${Qt5Core_INCLUDE_DIRS} |
||||
${Qt5DBus_INCLUDE_DIRS} |
||||
${Qt5Network_INCLUDE_DIRS} |
||||
${DDESESSIONSHELL_INCLUDE_DIR} |
||||
) |
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE |
||||
${PAM_LIBRARIES} |
||||
${Qt5Widgets_LIBRARIES} |
||||
${Qt5Core_LIBRARIES} |
||||
${Qt5DBus_LIBRARIES} |
||||
${Qt5Network_LIBRARIES} |
||||
) |
||||
@ -0,0 +1,18 @@ |
||||
#include "loginwidget.h" |
||||
#include "dp4_login_module.h" |
||||
|
||||
#include <QHBoxLayout> |
||||
|
||||
LoginWidget::LoginWidget(QWidget *parent) |
||||
: QWidget (parent) |
||||
, m_dp4module(new dss::module::Dp4LoginModule(this)) |
||||
{ |
||||
QHBoxLayout *layout = new QHBoxLayout(this); |
||||
layout->setContentsMargins(0, 0, 0, 0); |
||||
layout->setSpacing(0); |
||||
layout->addWidget(m_dp4module->content()); |
||||
} |
||||
|
||||
LoginWidget::~LoginWidget() |
||||
{ |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
#ifndef LOGINWIDGET_H |
||||
#define LOGINWIDGET_H |
||||
|
||||
#include <QWidget> |
||||
|
||||
namespace dss { |
||||
namespace module { |
||||
class Dp4LoginModule; |
||||
} |
||||
} |
||||
|
||||
class LoginWidget : public QWidget |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
LoginWidget(QWidget *parent = nullptr); |
||||
~LoginWidget(); |
||||
|
||||
private: |
||||
dss::module::Dp4LoginModule *m_dp4module; |
||||
}; |
||||
|
||||
#endif |
||||
@ -0,0 +1,47 @@ |
||||
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "serviceqtdbus.h" |
||||
#include "loginwidget.h" |
||||
#include "pamtest.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QDesktopWidget> |
||||
#include <QTranslator> |
||||
|
||||
#include <unistd.h> |
||||
|
||||
using namespace std; |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
QApplication app(argc, argv); |
||||
|
||||
if (QString(argv[1]) == "service") { |
||||
// 新建deepinServiceManager的服务
|
||||
QString fileName = QString("%1user/plugin-dp4-service.json").arg(SERVICE_CONFIG_DIR); |
||||
Policy policy(nullptr); |
||||
policy.parseConfig(fileName); |
||||
ServiceQtDBus service; |
||||
service.init(QDBusConnection::BusType::SessionBus, &policy); |
||||
return app.exec(); |
||||
} |
||||
|
||||
if (QString(argv[1]) == "login") { |
||||
// 登錄插件的demo
|
||||
LoginWidget widget; |
||||
widget.show(); |
||||
widget.resize(500, 500); |
||||
return app.exec(); |
||||
} |
||||
|
||||
if (QString(argv[1]) == "pam") { |
||||
// 測試pam
|
||||
PamTest test; |
||||
test.startPam(); |
||||
return app.exec(); |
||||
} |
||||
|
||||
return app.exec(); |
||||
} |
||||
@ -0,0 +1,57 @@ |
||||
#include "pamtest.h" |
||||
|
||||
#include <QDebug> |
||||
|
||||
#include <security/pam_appl.h> |
||||
|
||||
PamTest::PamTest(QObject *parent) |
||||
: QObject (parent) |
||||
{ |
||||
} |
||||
|
||||
PamTest::~PamTest() |
||||
{ |
||||
} |
||||
|
||||
void PamTest::startPam() |
||||
{ |
||||
pam_handle_t *pamHandle = nullptr; |
||||
pam_conv conv = {PAMConversation, static_cast<void *>(this)}; |
||||
// pam_start第一個參數對應於/etc/pam.d下面的指定的PAM文件,第二個參數對應於登錄的賬戶名
|
||||
int ret = pam_start("test_pam", "uos", &conv, &pamHandle); |
||||
if (ret != PAM_SUCCESS) { |
||||
//qCritical() << "ERROR: PAM start failed, error: " << pam_strerror(pamHandle, ret) << ", start infomation: " << ret;
|
||||
} else { |
||||
qDebug() << "PAM start..."; |
||||
} |
||||
|
||||
// 可以在此處設置密碼
|
||||
//const char *password = "testpassword";
|
||||
//pam_set_item(pamHandle, PAM_AUTHTOK, password);
|
||||
|
||||
int rc = pam_authenticate(pamHandle, 0); |
||||
if (rc != PAM_SUCCESS) { |
||||
//qWarning() << "PAM authenticate failed, error: " << pam_strerror(pamHandle, rc) << ", PAM authenticate: " << rc;
|
||||
} else { |
||||
qDebug() << "PAM authenticate finished."; |
||||
} |
||||
|
||||
int tmpRt = pam_acct_mgmt(pamHandle, 1); |
||||
if (tmpRt != PAM_SUCCESS) { |
||||
//qCritical() << "PAM acct failed:" << pam_strerror(pamHandle, tmpRt) << "PAM end infomation: " << tmpRt;
|
||||
} else { |
||||
qDebug() << "PAM acct finished."; |
||||
} |
||||
|
||||
int re = pam_end(pamHandle, rc); |
||||
if (re != PAM_SUCCESS) { |
||||
//qCritical() << "PAM end failed:" << pam_strerror(pamHandle, re) << "PAM end infomation: " << re;
|
||||
} else { |
||||
qDebug() << "PAM end..."; |
||||
} |
||||
} |
||||
|
||||
int PamTest::PAMConversation(int num_msg, const pam_message **msg, pam_response **resp, void *app_data) |
||||
{ |
||||
return PAM_SUCCESS; |
||||
} |
||||
@ -0,0 +1,23 @@ |
||||
#ifndef PAMTEST_H |
||||
#define PAMTEST_H |
||||
|
||||
#include <QObject> |
||||
|
||||
#include <security/_pam_types.h> |
||||
|
||||
class PamTest : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
PamTest(QObject *parent = nullptr); |
||||
~PamTest(); |
||||
|
||||
void startPam(); |
||||
|
||||
private: |
||||
static int PAMConversation(int num_msg, const pam_message **msg, pam_response **resp, void *app_data); |
||||
|
||||
}; |
||||
|
||||
#endif |
||||
@ -0,0 +1,542 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "policy.h" |
||||
|
||||
#include <QDebug> |
||||
#include <QFile> |
||||
#include <QJsonArray> |
||||
#include <QJsonDocument> |
||||
#include <QJsonObject> |
||||
#include <QLoggingCategory> |
||||
|
||||
Q_LOGGING_CATEGORY(dsm_policy, "[Policy]") |
||||
|
||||
Policy::Policy(QObject *parent) |
||||
: QObject(parent) |
||||
{ |
||||
} |
||||
|
||||
bool Policy::checkPathHide(const QString &path) |
||||
{ |
||||
QMapPathHide::iterator iter = mapPathHide.find(path); |
||||
if (iter == mapPathHide.end()) { |
||||
return false; |
||||
} |
||||
return iter.value(); |
||||
} |
||||
|
||||
bool Policy::checkMethodPermission(const QString &process, |
||||
const QString &path, |
||||
const QString &interface, |
||||
const QString &method) |
||||
{ |
||||
return checkPermission(process, path, interface, method, CallDestType::Method); |
||||
} |
||||
|
||||
bool Policy::checkPropertyPermission(const QString &process, |
||||
const QString &path, |
||||
const QString &interface, |
||||
const QString &property) |
||||
{ |
||||
return checkPermission(process, path, interface, property, CallDestType::Property); |
||||
} |
||||
|
||||
bool Policy::checkPermission(const QString &process, |
||||
const QString &path, |
||||
const QString &interface, |
||||
const QString &dest, |
||||
const CallDestType &type) |
||||
{ |
||||
qCInfo(dsm_policy) << "check permission:" |
||||
<< QString("process=%1, path=%2, interface=%3, dest=%4") |
||||
.arg(process, path, interface, dest); |
||||
// 时间复杂度跟权限配置复杂度正相关,简单的配置就会校验很快
|
||||
QMapPath::const_iterator iterPath = mapPath.find(path); |
||||
if (iterPath == mapPath.end()) { |
||||
// 默认不校验,即有权限
|
||||
return true; |
||||
} |
||||
|
||||
// PATH权限
|
||||
const PolicyPath &policyPath = iterPath.value(); |
||||
QMapInterface::const_iterator iterInterface = policyPath.interfaces.find(interface); |
||||
if (iterInterface == policyPath.interfaces.end()) { |
||||
// 没有配置interface权限,则用path权限
|
||||
if (!policyPath.needPermission) { |
||||
return true; |
||||
} |
||||
return policyPath.processes.contains(process); |
||||
} |
||||
|
||||
if (type == CallDestType::Method) { |
||||
// INTERFACE权限
|
||||
const PolicyInterface &policyInterface = iterInterface.value(); |
||||
QMapMethod::const_iterator iterMethod = policyInterface.methods.find(dest); |
||||
if (iterMethod == policyInterface.methods.end()) { |
||||
if (!policyInterface.needPermission) { |
||||
return true; |
||||
} |
||||
return policyInterface.processes.contains(process); |
||||
} |
||||
// METHOD权限
|
||||
const PolicyMethod &policyMethod = iterMethod.value(); |
||||
if (!policyMethod.needPermission) { |
||||
return true; |
||||
} |
||||
return policyMethod.processes.contains(process); |
||||
|
||||
} else if (type == CallDestType::Property) { |
||||
// INTERFACE权限
|
||||
const PolicyInterface &policyInterface = iterInterface.value(); |
||||
QMapProperty::const_iterator iterProp = policyInterface.properties.find(dest); |
||||
if (iterProp == policyInterface.properties.end()) { |
||||
if (!policyInterface.needPermission) { |
||||
return true; |
||||
} |
||||
return policyInterface.processes.contains(process); |
||||
} |
||||
// PROPERTY权限
|
||||
const PolicyProperty &policyProp = iterProp.value(); |
||||
if (!policyProp.needPermission) { |
||||
return true; |
||||
} |
||||
return policyProp.processes.contains(process); |
||||
} |
||||
|
||||
qCWarning(dsm_policy) << "check permission error!"; |
||||
return false; |
||||
} |
||||
|
||||
QStringList Policy::paths() const |
||||
{ |
||||
return mapSubPath.keys(); |
||||
} |
||||
|
||||
bool Policy::allowSubPath(const QString &path) const |
||||
{ |
||||
auto iter = mapSubPath.find(path); |
||||
if (iter != mapSubPath.end()) { |
||||
return iter.value(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool Policy::isResident() const |
||||
{ |
||||
return startType == "Resident"; |
||||
} |
||||
|
||||
void Policy::print() |
||||
{ |
||||
qInfo() << "-------------------------------------"; |
||||
qInfo() << "DBUS POLICY CONFIG"; |
||||
qInfo() << "- name:" << name; |
||||
qInfo() << "- path hide"; |
||||
for (QMapPathHide::iterator iter = mapPathHide.begin(); iter != mapPathHide.end(); iter++) { |
||||
qInfo() << "-- path hide:" << iter.key() << iter.value(); |
||||
} |
||||
qInfo() << "- whitelist"; |
||||
for (QMapWhitelists::iterator iter = mapWhitelist.begin(); iter != mapWhitelist.end(); iter++) { |
||||
qInfo() << "-- whitelist:" << iter.key() << iter.value().name << iter.value().process; |
||||
} |
||||
qInfo() << "- policy"; |
||||
for (QMapPath::iterator iter = mapPath.begin(); iter != mapPath.end(); iter++) { |
||||
qInfo() << "-- path:" << iter.key() << iter.value().path; |
||||
qInfo() << "-- permission:" << iter.value().needPermission; |
||||
qInfo() << "-- whitelist:" << iter.value().processes; |
||||
for (QMapInterface::iterator iterInterface = iter.value().interfaces.begin(); |
||||
iterInterface != iter.value().interfaces.end(); |
||||
iterInterface++) { |
||||
qInfo() << "---- interface:" << iterInterface.key() << iterInterface.value().interface; |
||||
qInfo() << "---- permission:" << iterInterface.value().needPermission; |
||||
qInfo() << "---- whitelist:" << iterInterface.value().processes; |
||||
for (QMapMethod::iterator iterMethod = iterInterface.value().methods.begin(); |
||||
iterMethod != iterInterface.value().methods.end(); |
||||
iterMethod++) { |
||||
qInfo() << "------ method:" << iterMethod.key() << iterMethod.value().method; |
||||
qInfo() << "------ permission:" << iterMethod.value().needPermission; |
||||
qInfo() << "------ whitelist:" << iterMethod.value().processes; |
||||
} |
||||
for (QMapProperty::iterator iterProp = iterInterface.value().properties.begin(); |
||||
iterProp != iterInterface.value().properties.end(); |
||||
iterProp++) { |
||||
qInfo() << "------ property:" << iterProp.key() << iterProp.value().property; |
||||
qInfo() << "------ permission:" << iterProp.value().needPermission; |
||||
qInfo() << "------ whitelist:" << iterProp.value().processes; |
||||
} |
||||
} |
||||
} |
||||
qInfo() << "-------------------------------------"; |
||||
} |
||||
|
||||
void Policy::parseConfig(const QString &path) |
||||
{ |
||||
qCInfo(dsm_policy) << "parse config:" << path; |
||||
if (path.isEmpty()) { |
||||
qCWarning(dsm_policy) << "path is empty!"; |
||||
return; |
||||
} |
||||
QJsonDocument jsonDoc; |
||||
if (!readJsonFile(jsonDoc, path)) { |
||||
qCWarning(dsm_policy) << "read json file failed!"; |
||||
return; |
||||
} |
||||
QJsonObject rootObj = jsonDoc.object(); |
||||
jsonGetString(rootObj, "name", name); |
||||
jsonGetString(rootObj, "group", group, "app"); |
||||
jsonGetString(rootObj, "libPath", pluginPath); // 兼容
|
||||
jsonGetString(rootObj, "pluginPath", pluginPath, pluginPath); |
||||
jsonGetString(rootObj, "policyVersion", version, "1.0"); // 兼容
|
||||
jsonGetString(rootObj, "version", version, version); |
||||
jsonGetString(rootObj, "policyStartType", startType, "Resident"); // 兼容
|
||||
jsonGetString(rootObj, "startType", startType, startType); |
||||
jsonGetStringList(rootObj, "dependencies", dependencies); |
||||
jsonGetInt(rootObj, "startDelay", startDelay, 0); |
||||
jsonGetInt(rootObj, "idleTime", idleTime, 10); |
||||
// get SDKType
|
||||
QString sdkTypeString; |
||||
jsonGetString(rootObj, "pluginType", sdkTypeString, "qt"); |
||||
if (sdkTypeString == "qt") |
||||
sdkType = SDKType::QT; |
||||
if (sdkTypeString == "sd") |
||||
sdkType = SDKType::SD; |
||||
|
||||
if (name.isEmpty()) { |
||||
qCWarning(dsm_policy) << "json error, name is empty."; |
||||
return; |
||||
} |
||||
if (!parseWhitelist(rootObj)) { |
||||
qCWarning(dsm_policy) << "json error, parse whitelist error."; |
||||
return; |
||||
} |
||||
|
||||
if (!parsePolicy(rootObj)) { |
||||
qCWarning(dsm_policy) << "json error, parse policy error."; |
||||
return; |
||||
} |
||||
} |
||||
|
||||
bool Policy::readJsonFile(QJsonDocument &outDoc, const QString &fileName) |
||||
{ |
||||
QFile jsonFIle(fileName); |
||||
if (!jsonFIle.open(QIODevice::ReadOnly)) { |
||||
qCWarning(dsm_policy) << QString("open file: %1 error!").arg(fileName); |
||||
return false; |
||||
} |
||||
|
||||
QJsonParseError jsonParserError; |
||||
outDoc = QJsonDocument::fromJson(jsonFIle.readAll(), &jsonParserError); |
||||
jsonFIle.close(); |
||||
if (jsonParserError.error != QJsonParseError::NoError) { |
||||
qCWarning(dsm_policy) << "to json document error: " << jsonParserError.errorString(); |
||||
return false; |
||||
} |
||||
if (outDoc.isNull()) { |
||||
qCWarning(dsm_policy) << "json document is null!"; |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// typedef QMap<QString, PolicyWhitelist> QMapWhitelists;
|
||||
bool Policy::parseWhitelist(const QJsonObject &obj) |
||||
{ |
||||
mapWhitelist.clear(); |
||||
if (!obj.contains("whitelists")) { |
||||
// 为空,不是出错
|
||||
return true; |
||||
} |
||||
QJsonValue listsValue = obj.value("whitelists"); |
||||
if (!listsValue.isArray()) { |
||||
qCWarning(dsm_policy) << "parse whitelist error, must be json array!"; |
||||
return false; |
||||
} |
||||
QJsonArray lists = listsValue.toArray(); |
||||
for (int i = 0; i < lists.size(); ++i) { |
||||
QJsonValue whitelistValue = lists.at(i); |
||||
if (whitelistValue.isObject()) { |
||||
PolicyWhitelist whitelist; |
||||
QJsonObject whitelistObj = whitelistValue.toObject(); |
||||
QString name; |
||||
jsonGetString(whitelistObj, "name", name); |
||||
if (name.isEmpty()) { |
||||
continue; |
||||
} |
||||
if (!whitelistObj.contains("process")) { |
||||
continue; |
||||
} |
||||
QJsonArray processes = whitelistObj.value("process").toArray(); |
||||
if (processes.size() <= 0) { |
||||
continue; |
||||
} |
||||
whitelist.name = name; |
||||
for (int j = 0; j < processes.size(); ++j) { |
||||
if (processes.at(j).isString()) { |
||||
whitelist.process.append(processes.at(j).toString()); |
||||
} |
||||
} |
||||
mapWhitelist.insert(name, whitelist); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool Policy::parsePolicy(const QJsonObject &obj) |
||||
{ |
||||
mapPathHide.clear(); |
||||
mapPath.clear(); |
||||
if (!obj.contains("policy")) { |
||||
// 为空,不是出错
|
||||
return true; |
||||
} |
||||
QJsonValue policyValue = obj.value("policy"); |
||||
if (!policyValue.isArray()) { |
||||
qCWarning(dsm_policy) << "parse policy error, must be json array!"; |
||||
return false; |
||||
} |
||||
QJsonArray policyList = policyValue.toArray(); |
||||
for (int i = 0; i < policyList.size(); ++i) { |
||||
QJsonValue policy = policyList.at(i); |
||||
if (!policy.isObject()) |
||||
continue; |
||||
if (!parsePolicyPath(policy.toObject())) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool Policy::parsePolicyPath(const QJsonObject &obj) |
||||
{ |
||||
QString path; |
||||
jsonGetString(obj, "path", path); |
||||
if (path.isEmpty()) { |
||||
qCWarning(dsm_policy) << "parse policy-path error, must be a string!"; |
||||
return false; |
||||
} |
||||
|
||||
bool pathHide; |
||||
jsonGetBool(obj, "pathhide", pathHide, false); |
||||
mapPathHide.insert(path, pathHide); |
||||
|
||||
bool subpath; |
||||
jsonGetBool(obj, "subpath", subpath, false); |
||||
mapSubPath.insert(path, pathHide); |
||||
|
||||
PolicyPath policyPath; |
||||
policyPath.path = path; |
||||
jsonGetBool(obj, "permission", policyPath.needPermission, false); |
||||
QString whitelist; |
||||
jsonGetString(obj, "whitelist", whitelist); |
||||
if (!whitelist.isEmpty()) { |
||||
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist); |
||||
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) { |
||||
policyPath.processes = iterWhitelist.value().process; |
||||
} |
||||
} |
||||
|
||||
if (obj.contains("interfaces")) { |
||||
QJsonValue interfaces = obj.value("interfaces"); |
||||
if (interfaces.isArray()) { |
||||
QJsonArray interfaceList = interfaces.toArray(); |
||||
for (int i = 0; i < interfaceList.size(); ++i) { |
||||
QJsonValue interface = interfaceList.at(i); |
||||
if (interface.isObject()) { |
||||
bool ret = parsePolicyInterface(interface.toObject(), policyPath); |
||||
if (!ret) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
mapPath.insert(path, policyPath); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool Policy::parsePolicyInterface(const QJsonObject &obj, PolicyPath &policyPath) |
||||
{ |
||||
QString interface; |
||||
jsonGetString(obj, "interface", interface); |
||||
if (interface.isEmpty()) { |
||||
qCWarning(dsm_policy) << "parse policy-interface error, must be a string!"; |
||||
return false; |
||||
} |
||||
|
||||
PolicyInterface policyInterface; |
||||
policyInterface.interface = interface; |
||||
// interface没有指定permission,则使用上级path的permission
|
||||
jsonGetBool(obj, "permission", policyInterface.needPermission, policyPath.needPermission); |
||||
QString whitelist; |
||||
jsonGetString(obj, "whitelist", whitelist); |
||||
if (!whitelist.isEmpty()) { |
||||
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist); |
||||
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) { |
||||
policyInterface.processes = iterWhitelist.value().process; |
||||
} // esle 错误的whitelist认为是空值
|
||||
} else { |
||||
// interface没有指定whitelist,则使用上级path的whitelist
|
||||
policyInterface.processes = policyPath.processes; |
||||
} |
||||
|
||||
if (obj.contains("methods")) { |
||||
QJsonValue methods = obj.value("methods"); |
||||
if (methods.isArray()) { |
||||
QJsonArray methodList = methods.toArray(); |
||||
for (int i = 0; i < methodList.size(); ++i) { |
||||
QJsonValue method = methodList.at(i); |
||||
if (method.isObject()) { |
||||
bool ret = parsePolicyMethod(method.toObject(), policyInterface); |
||||
if (!ret) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (obj.contains("properties")) { |
||||
QJsonValue properties = obj.value("properties"); |
||||
if (properties.isArray()) { |
||||
QJsonArray propertiesList = properties.toArray(); |
||||
for (int i = 0; i < propertiesList.size(); ++i) { |
||||
QJsonValue property = propertiesList.at(i); |
||||
if (property.isObject()) { |
||||
bool ret = parsePolicyProperties(property.toObject(), policyInterface); |
||||
if (!ret) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
policyPath.interfaces.insert(interface, policyInterface); |
||||
return true; |
||||
} |
||||
|
||||
bool Policy::parsePolicyMethod(const QJsonObject &obj, PolicyInterface &policyInterface) |
||||
{ |
||||
QString method; |
||||
jsonGetString(obj, "method", method); |
||||
if (method.isEmpty()) { |
||||
qCWarning(dsm_policy) << "parse policy-method error, must be a string!"; |
||||
return false; |
||||
} |
||||
|
||||
PolicyMethod policyMethod; |
||||
policyMethod.method = method; |
||||
// method没有指定permission,则使用上级interface的permission
|
||||
jsonGetBool(obj, "permission", policyMethod.needPermission, policyInterface.needPermission); |
||||
QString whitelist; |
||||
jsonGetString(obj, "whitelist", whitelist); |
||||
if (!whitelist.isEmpty()) { |
||||
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist); |
||||
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) { |
||||
policyMethod.processes = iterWhitelist.value().process; |
||||
} |
||||
} else { |
||||
// method没有指定whitelist,则使用上级interface的whitelist
|
||||
policyMethod.processes = policyInterface.processes; |
||||
} |
||||
|
||||
policyInterface.methods.insert(method, policyMethod); |
||||
return true; |
||||
} |
||||
|
||||
bool Policy::parsePolicyProperties(const QJsonObject &obj, PolicyInterface &policyInterface) |
||||
{ |
||||
QString property; |
||||
jsonGetString(obj, "property", property); |
||||
if (property.isEmpty()) { |
||||
qCWarning(dsm_policy) << "parse policy-property error, must be a string!"; |
||||
return false; |
||||
} |
||||
|
||||
PolicyProperty policyproperty; |
||||
policyproperty.property = property; |
||||
jsonGetBool(obj, "permission", policyproperty.needPermission, policyInterface.needPermission); |
||||
QString whitelist; |
||||
jsonGetString(obj, "whitelist", whitelist); |
||||
if (!whitelist.isEmpty()) { |
||||
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist); |
||||
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) { |
||||
policyproperty.processes = iterWhitelist.value().process; |
||||
} |
||||
} else { |
||||
policyproperty.processes = policyInterface.processes; |
||||
} |
||||
|
||||
policyInterface.properties.insert(property, policyproperty); |
||||
return true; |
||||
} |
||||
|
||||
bool Policy::jsonGetString(const QJsonObject &obj, |
||||
const QString &key, |
||||
QString &value, |
||||
QString defaultValue) |
||||
{ |
||||
if (obj.contains(key)) { |
||||
const QJsonValue &v = obj.value(key); |
||||
if (v.isString()) { |
||||
value = v.toString(); |
||||
return true; |
||||
} |
||||
} |
||||
value = defaultValue; |
||||
return false; |
||||
} |
||||
|
||||
bool Policy::jsonGetStringList(const QJsonObject &obj, |
||||
const QString &key, |
||||
QStringList &value, |
||||
QStringList defaultValue) |
||||
{ |
||||
value = defaultValue; |
||||
if (!obj.contains(key)) |
||||
return false; |
||||
const QJsonValue &v = obj.value(key); |
||||
if (v.isString()) { |
||||
value.append(v.toString()); |
||||
return true; |
||||
} |
||||
if (v.isArray()) { |
||||
const QJsonArray &array = v.toArray(); |
||||
for (auto &&a : array) { |
||||
if (a.isString()) |
||||
value.append(a.toString()); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool Policy::jsonGetBool(const QJsonObject &obj, const QString &key, bool &value, bool defaultValue) |
||||
{ |
||||
if (obj.contains(key)) { |
||||
const QJsonValue &v = obj.value(key); |
||||
if (v.isBool()) { |
||||
value = v.toBool(); |
||||
return true; |
||||
} |
||||
} |
||||
value = defaultValue; |
||||
return false; |
||||
} |
||||
|
||||
bool Policy::jsonGetInt(const QJsonObject &obj, const QString &key, int &value, int defaultValue) |
||||
{ |
||||
if (obj.contains(key)) { |
||||
const QJsonValue &v = obj.value(key); |
||||
if (v.isDouble()) { |
||||
value = v.toInt(); |
||||
return true; |
||||
} |
||||
} |
||||
value = defaultValue; |
||||
return false; |
||||
} |
||||
@ -0,0 +1,145 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef POLICY_H |
||||
#define POLICY_H |
||||
|
||||
#include <QMap> |
||||
#include <QObject> |
||||
|
||||
enum class SDKType { QT, SD }; |
||||
|
||||
struct PolicyWhitelist |
||||
{ |
||||
QString name; |
||||
QStringList process; |
||||
}; |
||||
|
||||
typedef QMap<QString, PolicyWhitelist> QMapWhitelists; |
||||
// hide, default:false
|
||||
typedef QMap<QString, bool> QMapPathHide; |
||||
// subpath, default:false
|
||||
typedef QMap<QString, bool> QMapSubPath; |
||||
|
||||
// typedef QMap<QString, bool> QMapProcess;
|
||||
struct PolicyMethod |
||||
{ |
||||
QString method; |
||||
bool needPermission; |
||||
QStringList processes; |
||||
}; |
||||
|
||||
typedef QMap<QString, PolicyMethod> QMapMethod; |
||||
|
||||
struct PolicyProperty |
||||
{ |
||||
QString property; |
||||
bool needPermission; |
||||
QStringList processes; |
||||
}; |
||||
|
||||
typedef QMap<QString, PolicyProperty> QMapProperty; |
||||
|
||||
struct PolicyInterface |
||||
{ |
||||
QString interface; |
||||
bool needPermission; |
||||
QStringList processes; |
||||
QMapMethod methods; |
||||
QMapProperty properties; |
||||
}; |
||||
|
||||
typedef QMap<QString, PolicyInterface> QMapInterface; |
||||
|
||||
struct PolicyPath |
||||
{ |
||||
QString path; |
||||
bool needPermission; |
||||
QStringList processes; |
||||
QMapInterface interfaces; |
||||
}; |
||||
|
||||
typedef QMap<QString, PolicyPath> QMapPath; |
||||
|
||||
enum CallDestType { Method, Property }; |
||||
|
||||
class Policy : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit Policy(QObject *parent = nullptr); |
||||
|
||||
void parseConfig(const QString &path); |
||||
|
||||
bool checkPathHide(const QString &path); |
||||
bool checkMethodPermission(const QString &process, |
||||
const QString &path, |
||||
const QString &interface, |
||||
const QString &method); |
||||
bool checkPropertyPermission(const QString &process, |
||||
const QString &path, |
||||
const QString &interface, |
||||
const QString &property); |
||||
bool checkPermission(const QString &process, |
||||
const QString &path, |
||||
const QString &interface, |
||||
const QString &dest, |
||||
const CallDestType &type); |
||||
QStringList paths() const; |
||||
bool allowSubPath(const QString &path) const; |
||||
bool isResident() const; |
||||
|
||||
// void Check(); // TODO
|
||||
void print(); |
||||
|
||||
private: |
||||
bool readJsonFile(QJsonDocument &outDoc, const QString &fileName); |
||||
bool parseWhitelist(const QJsonObject &obj); |
||||
bool parsePolicy(const QJsonObject &obj); |
||||
bool parsePolicyPath(const QJsonObject &obj); |
||||
bool parsePolicyInterface(const QJsonObject &obj, PolicyPath &policyPath); |
||||
bool parsePolicyMethod(const QJsonObject &obj, PolicyInterface &policyInterface); |
||||
bool parsePolicyProperties(const QJsonObject &obj, PolicyInterface &policyInterface); |
||||
|
||||
bool jsonGetString(const QJsonObject &obj, |
||||
const QString &key, |
||||
QString &value, |
||||
QString defaultValue = ""); |
||||
bool jsonGetStringList(const QJsonObject &obj, |
||||
const QString &key, |
||||
QStringList &value, |
||||
QStringList defaultValue = {}); |
||||
bool |
||||
jsonGetBool(const QJsonObject &obj, const QString &key, bool &value, bool defaultValue = false); |
||||
bool jsonGetInt(const QJsonObject &obj, const QString &key, int &value, int defaultValue = 0); |
||||
|
||||
public: |
||||
// 数据定义
|
||||
// 插入速度要求不高,查询速度要求很高,因此解析json的结果会通过冗余、预处理来提高查询速度,即以查询的速度角度来定义结构
|
||||
// 配置文件和此处数据没有一一对应,解析文件时,需要为此处数据服务,填充相关数据
|
||||
// 如果文件没有配置某参数,那也不允许空值,根据数据向下继承,比如某个参数interface没有设置,则interface的这个参数继承path
|
||||
// 不允许空值的作用是减少查询时的逻辑判断,把这些逻辑处理转移到解析文件阶段
|
||||
// 隐藏 - In:path,Out:pathhide
|
||||
// 权限PATH - In:process、path,Out:bool
|
||||
// 权限INTERFACE - In:process、path、interface,Out:bool
|
||||
// 权限METHOD - In:process、path、interface、method,Out:bool
|
||||
// 权限PROPERTIES - In:process、path、interface,Out:bool
|
||||
QMapWhitelists mapWhitelist; |
||||
QMapPathHide mapPathHide; |
||||
QMapSubPath mapSubPath; |
||||
QMapPath mapPath; |
||||
|
||||
public: |
||||
QString name; |
||||
QString group; |
||||
QString pluginPath; |
||||
QString version; |
||||
QString startType; |
||||
QStringList dependencies; |
||||
SDKType sdkType; |
||||
int startDelay; |
||||
int idleTime; |
||||
}; |
||||
|
||||
#endif // POLICY_H
|
||||
@ -0,0 +1,276 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "qtdbushook.h" |
||||
|
||||
#include "policy.h" |
||||
#include "serviceqtdbus.h" |
||||
|
||||
#include <QDBusConnectionInterface> |
||||
#include <QDBusMessage> |
||||
#include <QDebug> |
||||
#include <QFile> |
||||
#include <QLoggingCategory> |
||||
#include <QTimer> |
||||
|
||||
#ifdef Q_DBUS_EXPORT |
||||
extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &)); |
||||
extern Q_DBUS_EXPORT void qDBusAddFilterHook(int (*)(const QString &, const QDBusMessage &)); |
||||
#else |
||||
extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &)); |
||||
extern QDBUS_EXPORT void qDBusAddFilterHook(int (*)(const QString &, const QDBusMessage &)); |
||||
#endif |
||||
|
||||
#ifdef Q_DBUS_HOOK_FILTER |
||||
# define HOOK_RESULT_TYPE int |
||||
# define HOOK_RESULT_SUCCESS 0 |
||||
# define HOOK_RESULT_FAILED -1 |
||||
#else |
||||
# define HOOK_RESULT_TYPE void |
||||
# define HOOK_RESULT_SUCCESS |
||||
# define HOOK_RESULT_FAILED |
||||
#endif |
||||
|
||||
Q_LOGGING_CATEGORY(dsm_hook_qt, "[QDBusHook]") |
||||
|
||||
QString getCMD(ServiceBase *obj, QString dbusService) |
||||
{ |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(obj); |
||||
if (!srv) { |
||||
return ""; |
||||
} |
||||
const unsigned int &pid = srv->qDbusConnection().interface()->servicePid(dbusService).value(); |
||||
qCDebug(dsm_hook_qt) << "--pid:" << pid; |
||||
QFile procCmd("/proc/" + QString::number(pid) + "/cmdline"); |
||||
QString cmd; |
||||
if (procCmd.open(QIODevice::ReadOnly)) { |
||||
QList<QByteArray> cmds = procCmd.readAll().split('\0'); |
||||
cmd = QString(cmds.first()); |
||||
qCDebug(dsm_hook_qt) << "--cmd:" << cmd; |
||||
} |
||||
return cmd; |
||||
} |
||||
|
||||
// if it is not a local message, hook exec at main thread
|
||||
void QTDBusSpyHook(const QDBusMessage &msg) |
||||
{ |
||||
qCInfo(dsm_hook_qt) << "--msg=" << msg; |
||||
// qInfo() << "--Handler ThreadID:" << QThread::currentThreadId();
|
||||
|
||||
ServiceBase *serviceObj = nullptr; |
||||
bool isSubPath; |
||||
QString realPath; // 子PATH可能没有配置,使用父PATH的配置
|
||||
bool findRet = QTDbusHook::instance()->getServiceObject("", |
||||
msg.path(), |
||||
&serviceObj, |
||||
isSubPath, |
||||
realPath); |
||||
if (!findRet) { |
||||
qCWarning(dsm_hook_qt) << "--can not find hook object: " << msg.path(); |
||||
return; |
||||
} |
||||
if (!serviceObj->isRegister()) { |
||||
qCInfo(dsm_hook_qt) << "--to register dbus object: " << msg.path(); |
||||
serviceObj->registerService(); |
||||
} |
||||
|
||||
if (!serviceObj->policy->isResident() && !serviceObj->isLockTimer()) { |
||||
qCInfo(dsm_hook_qt) << QString("--service: %1 will unregister in %2 minutes!") |
||||
.arg(serviceObj->policy->name) |
||||
.arg(serviceObj->policy->idleTime); |
||||
QTimer::singleShot(0, serviceObj, SLOT(restartTimer())); |
||||
} |
||||
if (msg.member() == "Introspect" && msg.interface() == "org.freedesktop.DBus.Introspectable") { |
||||
if (serviceObj->policy->checkPathHide(realPath)) { |
||||
qCDebug(dsm_hook_qt) << "--call Introspect" << msg.path() << " ,is hided!"; |
||||
QList<QVariant> arguments; |
||||
arguments << ""; |
||||
QDBusMessage reply = msg.createReply(arguments); |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj); |
||||
if (srv) { |
||||
srv->qDbusConnection().send(reply); |
||||
} |
||||
// ((ServiceQtDBus*)serviceObj)->qDbusConnection().send(reply);
|
||||
} |
||||
} else if (msg.member() == "Set" && msg.interface() == "org.freedesktop.DBus.Properties") { |
||||
const QList<QVariant> &args = msg.arguments(); |
||||
if (args.size() >= 2) { |
||||
if (!serviceObj->policy->checkPropertyPermission(getCMD(serviceObj, msg.service()), |
||||
realPath, |
||||
args.at(0).toString(), |
||||
args.at(1).toString())) { |
||||
QDBusMessage reply = msg.createErrorReply("com.deepin.service.Permission.Deny", |
||||
"The call is deny"); |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj); |
||||
if (srv) { |
||||
srv->qDbusConnection().send(reply); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} else if (msg.interface() != "org.freedesktop.DBus.Properties" |
||||
&& msg.interface() != "org.freedesktop.DBus.Introspectable" |
||||
&& msg.interface() != "org.freedesktop.DBus.Peer") { |
||||
if (!serviceObj->policy->checkMethodPermission(getCMD(serviceObj, msg.service()), |
||||
realPath, |
||||
msg.interface(), |
||||
msg.member())) { |
||||
QDBusMessage reply = |
||||
msg.createErrorReply("com.deepin.service.Permission.Deny", "The call is deny2"); |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj); |
||||
if (srv) { |
||||
// srv->qDbusConnection().send(reply);
|
||||
// QDBusConnection::sessionBus().send(reply);
|
||||
QDBusConnection::connectToBus(QDBusConnection::SessionBus, |
||||
QString("org.dsdsf.dsfsdf")) |
||||
.send(reply); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
return; |
||||
} |
||||
|
||||
// if it is not a local message, hook exec at main thread
|
||||
int QTDBusHook(const QString &baseService, const QDBusMessage &msg) |
||||
{ |
||||
qCInfo(dsm_hook_qt) << "--baseService=" << baseService; |
||||
qCInfo(dsm_hook_qt) << "--msg=" << msg; |
||||
// qInfo() << "--Handler ThreadID:" << QThread::currentThreadId();
|
||||
|
||||
ServiceBase *serviceObj = nullptr; |
||||
bool isSubPath; |
||||
QString realPath; // 子PATH可能没有配置,使用父PATH的配置
|
||||
bool findRet = QTDbusHook::instance()->getServiceObject("", |
||||
msg.path(), |
||||
&serviceObj, |
||||
isSubPath, |
||||
realPath); |
||||
if (!findRet) { |
||||
qCWarning(dsm_hook_qt) << "--can not find hook object:" << msg.path(); |
||||
return 0; |
||||
} |
||||
if (!serviceObj->isRegister()) { |
||||
qCInfo(dsm_hook_qt) << "--to register dbus object: " << msg.path(); |
||||
serviceObj->registerService(); |
||||
} |
||||
|
||||
if (!serviceObj->policy->isResident() && !serviceObj->isLockTimer()) { |
||||
qCInfo(dsm_hook_qt) << QString("--service: %1 will unregister in 10 minutes!") |
||||
.arg(serviceObj->policy->name); |
||||
QTimer::singleShot(0, serviceObj, SLOT(restartTimer())); |
||||
} |
||||
if (msg.member() == "Introspect" && msg.interface() == "org.freedesktop.DBus.Introspectable") { |
||||
if (serviceObj->policy->checkPathHide(realPath)) { |
||||
qCDebug(dsm_hook_qt) << "--call Introspect" << msg.path() << " ,is hided!"; |
||||
QList<QVariant> arguments; |
||||
arguments << ""; |
||||
QDBusMessage reply = msg.createReply(arguments); |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj); |
||||
if (srv) { |
||||
srv->qDbusConnection().send(reply); |
||||
} |
||||
// ((ServiceQtDBus*)serviceObj)->qDbusConnection().send(reply);
|
||||
} |
||||
} else if (msg.member() == "Set" && msg.interface() == "org.freedesktop.DBus.Properties") { |
||||
const QList<QVariant> &args = msg.arguments(); |
||||
if (args.size() >= 2) { |
||||
if (!serviceObj->policy->checkPropertyPermission(getCMD(serviceObj, msg.service()), |
||||
realPath, |
||||
args.at(0).toString(), |
||||
args.at(1).toString())) { |
||||
QDBusMessage reply = msg.createErrorReply("com.deepin.service.Permission.Deny", |
||||
"The call is deny"); |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj); |
||||
if (srv) { |
||||
srv->qDbusConnection().send(reply); |
||||
return -1; |
||||
} |
||||
} |
||||
} |
||||
} else if (msg.interface() != "org.freedesktop.DBus.Properties" |
||||
&& msg.interface() != "org.freedesktop.DBus.Introspectable" |
||||
&& msg.interface() != "org.freedesktop.DBus.Peer") { |
||||
if (!serviceObj->policy->checkMethodPermission(getCMD(serviceObj, msg.service()), |
||||
realPath, |
||||
msg.interface(), |
||||
msg.member())) { |
||||
QDBusMessage reply = |
||||
msg.createErrorReply("com.deepin.service.Permission.Deny", "The call is deny2"); |
||||
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj); |
||||
if (srv) { |
||||
srv->qDbusConnection().send(reply); |
||||
return -1; |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
|
||||
// test TODO
|
||||
// if (msg.member() == "Register") {
|
||||
// Policy ppp;
|
||||
// ppp.Test();
|
||||
// QList<QVariant> arguments;
|
||||
// arguments << true << "sdvvv";
|
||||
|
||||
// QDBusMessage reply =
|
||||
// msg.createErrorReply("com.deepin.services.Nooooooo", "The method
|
||||
// call 'Register()' is not supported");
|
||||
// QDBusConnection::connectToBus(QDBusConnection::SessionBus,
|
||||
// "org.deepin.services.demo2").send(reply);
|
||||
// }
|
||||
} |
||||
|
||||
Q_GLOBAL_STATIC(QTDbusHook, qtDBusHook) |
||||
|
||||
QTDbusHook::QTDbusHook() |
||||
{ |
||||
qCDebug(dsm_hook_qt) << "qt hook register."; |
||||
#ifdef Q_DBUS_HOOK_FILTER |
||||
qDBusAddFilterHook(QTDBusHook); |
||||
#else |
||||
qDBusAddSpyHook(QTDBusSpyHook); |
||||
#endif |
||||
} |
||||
|
||||
QTDbusHook *QTDbusHook::instance() |
||||
{ |
||||
return qtDBusHook; |
||||
} |
||||
|
||||
bool QTDbusHook::getServiceObject( |
||||
QString name, QString path, ServiceBase **service, bool &isSubPath, QString &realPath) |
||||
{ |
||||
Q_UNUSED(name) // TODO:QtDBus Hook 无法获取到name
|
||||
ServiceObjectMap::iterator iterService = m_serviceMap.find(path); |
||||
if (iterService != m_serviceMap.end()) { |
||||
*service = iterService.value(); |
||||
isSubPath = true; |
||||
realPath = iterService.key(); |
||||
return true; |
||||
} |
||||
for (auto iter = m_serviceMap.begin(); iter != m_serviceMap.end(); ++iter) { |
||||
if (path.startsWith(iter.key()) && iter.value()->policy->allowSubPath(iter.key())) { |
||||
*service = iter.value(); |
||||
isSubPath = false; |
||||
realPath = iter.key(); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool QTDbusHook::setServiceObject(ServiceBase *obj) |
||||
{ |
||||
QStringList paths = obj->policy->paths(); |
||||
for (auto path : paths) { |
||||
ServiceObjectMap::iterator iterService = m_serviceMap.find(path); |
||||
if (iterService != m_serviceMap.end()) { |
||||
qCWarning(dsm_hook_qt) << "set service path failed, the object is existed: " << path; |
||||
continue; |
||||
} |
||||
m_serviceMap[path] = obj; |
||||
} |
||||
return true; |
||||
} |
||||
@ -0,0 +1,28 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef QTDBUSHOOK_H |
||||
#define QTDBUSHOOK_H |
||||
|
||||
#include "servicebase.h" |
||||
|
||||
typedef QMap<QString, ServiceBase *> ServiceObjectMap; |
||||
|
||||
class QTDbusHook |
||||
{ |
||||
public: |
||||
explicit QTDbusHook(); |
||||
|
||||
bool getServiceObject( |
||||
QString name, QString path, ServiceBase **service, bool &isSubPath, QString &realPath); |
||||
|
||||
bool setServiceObject(ServiceBase *obj); |
||||
|
||||
static QTDbusHook *instance(); |
||||
|
||||
private: |
||||
ServiceObjectMap m_serviceMap; |
||||
}; |
||||
|
||||
#endif // QTDBUSHOOK_H
|
||||
@ -0,0 +1,77 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "servicebase.h" |
||||
|
||||
#include "policy.h" |
||||
|
||||
#include <QDBusConnection> |
||||
#include <QDBusMessage> |
||||
#include <QDebug> |
||||
#include <QThread> |
||||
#include <QTimer> |
||||
|
||||
ServiceBase::ServiceBase(QObject *parent) |
||||
: QObject(parent) |
||||
, policy(nullptr) |
||||
, m_isRegister(false) |
||||
, m_isLockTimer(false) |
||||
, m_timer(new QTimer(this)) |
||||
{ |
||||
m_timer->setSingleShot(true); |
||||
m_timer->setInterval(10 * 60 * 1000); // 设置超时时间, 默认10分钟
|
||||
connect(m_timer, &QTimer::timeout, this, &ServiceBase::idleSignal); |
||||
} |
||||
|
||||
ServiceBase::~ServiceBase() { } |
||||
|
||||
void ServiceBase::init(const QDBusConnection::BusType &busType, Policy *p) |
||||
{ |
||||
m_sessionType = busType; |
||||
policy = p; |
||||
p->setParent(this); |
||||
// p->Print();
|
||||
|
||||
m_timer->setInterval(policy->idleTime * 60 * 1000); // 设置超时时间
|
||||
connect(this, &ServiceBase::idleSignal, this, &ServiceBase::unregisterService); |
||||
initService(); |
||||
} |
||||
|
||||
void ServiceBase::initService() |
||||
{ |
||||
QThread *th = new QThread(); |
||||
setParent(nullptr); |
||||
moveToThread(th); |
||||
connect(th, &QThread::started, this, &ServiceBase::initThread); |
||||
th->start(); |
||||
} |
||||
|
||||
void ServiceBase::initThread() { } |
||||
|
||||
bool ServiceBase::isRegister() const |
||||
{ |
||||
return m_isRegister; |
||||
} |
||||
|
||||
bool ServiceBase::isLockTimer() const |
||||
{ |
||||
return m_isLockTimer; |
||||
} |
||||
|
||||
void ServiceBase::restartTimer() |
||||
{ |
||||
m_timer->start(); |
||||
} |
||||
|
||||
bool ServiceBase::registerService() |
||||
{ |
||||
m_isRegister = true; |
||||
return true; |
||||
} |
||||
|
||||
bool ServiceBase::unregisterService() |
||||
{ |
||||
m_isRegister = false; |
||||
return true; |
||||
} |
||||
@ -0,0 +1,54 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SERVICEBASE_H |
||||
#define SERVICEBASE_H |
||||
|
||||
#include "policy.h" |
||||
|
||||
#include <QDBusConnection> |
||||
#include <QObject> |
||||
|
||||
typedef void *(*ServiceObject)(const char *path, const int len); |
||||
typedef int (*DSMRegister)(const char *name, void *data); |
||||
typedef int (*DSMUnRegister)(const char *name, void *data); |
||||
|
||||
class QTimer; |
||||
|
||||
class ServiceBase : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit ServiceBase(QObject *parent = nullptr); |
||||
virtual ~ServiceBase(); |
||||
|
||||
bool isRegister() const; |
||||
bool isLockTimer() const; |
||||
virtual bool registerService(); |
||||
virtual bool unregisterService(); |
||||
|
||||
Q_SIGNALS: |
||||
void idleSignal(); |
||||
|
||||
public Q_SLOTS: |
||||
void init(const QDBusConnection::BusType &busType, Policy *p); |
||||
void restartTimer(); |
||||
|
||||
protected: |
||||
virtual void initService(); |
||||
virtual void initThread(); |
||||
|
||||
public: |
||||
Policy *policy; |
||||
|
||||
protected: |
||||
bool m_isRegister; |
||||
bool m_isLockTimer; |
||||
|
||||
QDBusConnection::BusType m_sessionType; |
||||
SDKType m_SDKType; // qdbus、sdbus
|
||||
QTimer *m_timer; |
||||
}; |
||||
|
||||
#endif // SERVICEBASE_H
|
||||
@ -0,0 +1,106 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "serviceqtdbus.h" |
||||
|
||||
#include "policy.h" |
||||
#include "qtdbushook.h" |
||||
|
||||
#include <QDBusAbstractAdaptor> |
||||
#include <QDebug> |
||||
#include <QFileInfo> |
||||
#include <QLibrary> |
||||
#include <QLoggingCategory> |
||||
#include <QMetaClassInfo> |
||||
#include <QThread> |
||||
|
||||
Q_LOGGING_CATEGORY(dsm_service_qt, "[QDBusService]") |
||||
|
||||
ServiceQtDBus::ServiceQtDBus(QObject *parent) |
||||
: ServiceBase(parent) |
||||
, m_library(nullptr) |
||||
{ |
||||
m_SDKType = SDKType::QT; |
||||
} |
||||
|
||||
QDBusConnection ServiceQtDBus::qDbusConnection() |
||||
{ |
||||
if (policy->name.isEmpty()) { |
||||
return m_sessionType == QDBusConnection::SystemBus ? QDBusConnection::systemBus() : QDBusConnection::sessionBus(); |
||||
} |
||||
|
||||
return m_sessionType == QDBusConnection::SystemBus ? QDBusConnection::connectToBus(QDBusConnection::SystemBus, policy->name) |
||||
: QDBusConnection::connectToBus(QDBusConnection::SessionBus, policy->name); |
||||
} |
||||
|
||||
void ServiceQtDBus::initThread() |
||||
{ |
||||
qCInfo(dsm_service_qt) << "init service: " << policy->name << "paths: " << policy->paths(); |
||||
qDbusConnection().registerService(policy->name); |
||||
|
||||
// TODO: 无权限、隐藏、按需启动需求的service,不应该注册,避免触发hook,提高效率
|
||||
QTDbusHook::instance()->setServiceObject(this); |
||||
|
||||
QFileInfo fileInfo(QString(SERVICE_LIB_DIR) + policy->pluginPath); |
||||
if (QLibrary::isLibrary(fileInfo.absoluteFilePath())) { |
||||
qCInfo(dsm_service_qt) << "init library: " << fileInfo.absoluteFilePath(); |
||||
m_library = new QLibrary(fileInfo.absoluteFilePath()); |
||||
} |
||||
|
||||
if (!registerService()) { |
||||
qCWarning(dsm_service_qt) << "register service failed: " << policy->name; |
||||
} |
||||
ServiceBase::initThread(); |
||||
} |
||||
|
||||
bool ServiceQtDBus::registerService() |
||||
{ |
||||
qCInfo(dsm_service_qt) << "service register: " << policy->name; |
||||
|
||||
if (libFuncCall("DSMRegister", true)) { |
||||
ServiceBase::registerService(); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool ServiceQtDBus::unregisterService() |
||||
{ |
||||
qCInfo(dsm_service_qt) << "service unregister: " << policy->name; |
||||
|
||||
if (libFuncCall("DSMUnRegister", false)) { |
||||
ServiceBase::unregisterService(); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool ServiceQtDBus::libFuncCall(const QString &funcName, bool isRegister) |
||||
{ |
||||
if (m_library == nullptr) { |
||||
return false; |
||||
} |
||||
auto objFunc = isRegister ? DSMRegister(m_library->resolve(funcName.toStdString().c_str())) |
||||
: DSMUnRegister(m_library->resolve(funcName.toStdString().c_str())); |
||||
if (!objFunc) { |
||||
qCWarning(dsm_service_qt) |
||||
<< QString("failed to resolve the method: %1\n file: %2\n error message: %3") |
||||
.arg(funcName) |
||||
.arg(m_library->fileName()) |
||||
.arg(m_library->errorString()); |
||||
if (m_library->isLoaded()) |
||||
m_library->unload(); |
||||
m_library->deleteLater(); |
||||
return false; |
||||
} |
||||
auto connection = qDbusConnection(); |
||||
int ret = objFunc(policy->name.toStdString().c_str(), (void *)&connection); |
||||
if (ret) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
@ -0,0 +1,33 @@ |
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SERVICEQTDBUS_H |
||||
#define SERVICEQTDBUS_H |
||||
|
||||
#include "servicebase.h" |
||||
|
||||
class QLibrary; |
||||
|
||||
class ServiceQtDBus : public ServiceBase |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit ServiceQtDBus(QObject *parent = nullptr); |
||||
|
||||
QDBusConnection qDbusConnection(); |
||||
|
||||
virtual bool registerService() override; |
||||
virtual bool unregisterService() override; |
||||
|
||||
protected: |
||||
virtual void initThread() override; |
||||
|
||||
private: |
||||
bool libFuncCall(const QString &funcName, bool isRegister); |
||||
|
||||
private: |
||||
QLibrary *m_library; |
||||
}; |
||||
|
||||
#endif // SERVICEQTDBUS_H
|
||||
@ -0,0 +1,6 @@ |
||||
cd dp4-dbus-service |
||||
sh ./lupdate.sh |
||||
cd .. |
||||
cd dp4-login-plugin |
||||
sh ./lupdate.sh |
||||
cd .. |
||||
Loading…
Reference in new issue